HHH-6054 improve error checking

This commit is contained in:
Gavin King 2021-09-11 14:41:37 +02:00 committed by Steve Ebersole
parent 8af548b52d
commit ea0dd35362
4 changed files with 104 additions and 20 deletions

View File

@ -15,6 +15,7 @@ import jakarta.persistence.Lob;
import org.hibernate.AnnotationException; import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.annotations.AttributeAccessor; import org.hibernate.annotations.AttributeAccessor;
import org.hibernate.annotations.Generated; import org.hibernate.annotations.Generated;
import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Immutable;
@ -52,6 +53,8 @@ import org.hibernate.tuple.TenantIdGeneration;
import org.hibernate.tuple.ValueGeneration; import org.hibernate.tuple.ValueGeneration;
import org.hibernate.tuple.ValueGenerator; import org.hibernate.tuple.ValueGenerator;
import org.hibernate.type.BasicType;
import org.hibernate.type.Type;
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import static java.util.Collections.emptyMap; import static java.util.Collections.emptyMap;
@ -204,30 +207,58 @@ public class PropertyBinder {
setValue( propertyValue ); setValue( propertyValue );
Property prop = makeProperty(); Property prop = makeProperty();
makeTenantIdFilter();
return prop;
}
private void makeTenantIdFilter() {
if ( property.isAnnotationPresent(TenantId.class) ) { if ( property.isAnnotationPresent(TenantId.class) ) {
InFlightMetadataCollector collector = buildingContext.getMetadataCollector(); InFlightMetadataCollector collector = buildingContext.getMetadataCollector();
BasicType<Object> tenantIdType =
collector.getTypeConfiguration().getBasicTypeRegistry()
.getRegisteredType(returnedClassName);
FilterDefinition filterDefinition = collector.getFilterDefinition(TenantIdGeneration.FILTER_NAME);
if ( filterDefinition == null ) {
collector.addFilterDefinition( collector.addFilterDefinition(
new FilterDefinition( new FilterDefinition(
TenantIdGeneration.FILTER_NAME, TenantIdGeneration.FILTER_NAME,
"", "",
singletonMap( singletonMap( TenantIdGeneration.PARAMETER_NAME, tenantIdType )
TenantIdGeneration.PARAMETER_NAME,
collector.getTypeConfiguration().getBasicTypeRegistry()
.getRegisteredType(returnedClassName)
)
) )
); );
String columnOrFormula = columns[0].isFormula() ? columns[0].getFormulaString() : columns[0].getName(); }
else {
Type parameterType = filterDefinition.getParameterTypes().get(TenantIdGeneration.PARAMETER_NAME);
if ( !parameterType.getName().equals( tenantIdType.getName() ) ) {
throw new MappingException(
"all @TenantId fields must have the same type: "
+ parameterType.getName()
+ " differs from "
+ tenantIdType.getName()
);
}
}
entityBinder.getPersistentClass() entityBinder.getPersistentClass()
.addFilter( .addFilter(
TenantIdGeneration.FILTER_NAME, TenantIdGeneration.FILTER_NAME,
columnOrFormula + " = :" + TenantIdGeneration.PARAMETER_NAME, getColumnNameOrFormula()
+ " = :"
+ TenantIdGeneration.PARAMETER_NAME,
true, true,
emptyMap(), emptyMap() emptyMap(),
emptyMap()
); );
} }
}
return prop; private String getColumnNameOrFormula() {
if ( columns.length!=1 ) {
throw new MappingException("@TenantId field must be mapped to a single column or formula");
}
return columns[0].isFormula()
? columns[0].getFormulaString()
: columns[0].getName();
} }
//used when value is provided //used when value is provided

View File

@ -11,6 +11,7 @@ import org.hibernate.annotations.TenantId;
import javax.persistence.Entity; import javax.persistence.Entity;
import javax.persistence.GeneratedValue; import javax.persistence.GeneratedValue;
import javax.persistence.Id; import javax.persistence.Id;
import javax.persistence.ManyToOne;
@Entity @Entity
public class Account { public class Account {
@ -19,5 +20,12 @@ public class Account {
@TenantId String tenantId; @TenantId String tenantId;
public Account() {} @ManyToOne Client client;
public Account(Client client) {
this.client = client;
} }
Account() {}
}

View File

@ -0,0 +1,37 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.test.tenantid;
import org.hibernate.annotations.TenantId;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import java.util.HashSet;
import java.util.Set;
@Entity
public class Client {
@Id
@GeneratedValue
Long id;
String name;
@TenantId
String tenantId;
@OneToMany(mappedBy = "client")
Set<Account> accounts = new HashSet<>();
public Client(String name) {
this.name = name;
}
Client() {}
}

View File

@ -24,7 +24,7 @@ import static org.hibernate.cfg.AvailableSettings.HBM2DDL_DATABASE_ACTION;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
@SessionFactory @SessionFactory
@DomainModel(annotatedClasses = Account.class) @DomainModel(annotatedClasses = { Account.class, Client.class })
@ServiceRegistry( @ServiceRegistry(
settings = { settings = {
@Setting(name = HBM2DDL_DATABASE_ACTION, value = "create-drop") @Setting(name = HBM2DDL_DATABASE_ACTION, value = "create-drop")
@ -53,8 +53,12 @@ public class TenantIdTest implements SessionFactoryProducer {
@Test @Test
public void test(SessionFactoryScope scope) { public void test(SessionFactoryScope scope) {
currentTenant = "mine"; currentTenant = "mine";
Account acc = new Account(); Client client = new Client("Gavin");
scope.inTransaction( session -> session.persist(acc) ); Account acc = new Account(client);
scope.inTransaction( session -> {
session.persist(client);
session.persist(acc);
} );
scope.inTransaction( session -> { scope.inTransaction( session -> {
assertNotNull( session.find(Account.class, acc.id) ); assertNotNull( session.find(Account.class, acc.id) );
assertEquals( 1, session.createQuery("from Account").getResultList().size() ); assertEquals( 1, session.createQuery("from Account").getResultList().size() );
@ -71,10 +75,14 @@ public class TenantIdTest implements SessionFactoryProducer {
@Test @Test
public void testError(SessionFactoryScope scope) { public void testError(SessionFactoryScope scope) {
currentTenant = "mine"; currentTenant = "mine";
Client client = new Client("Gavin");
Account acc = new Account(); Account acc = new Account();
acc.tenantId = "yours"; acc.tenantId = "yours";
try { try {
scope.inTransaction( session -> session.persist(acc) ); scope.inTransaction( session -> {
session.persist(client);
session.persist(acc);
} );
fail("should have thrown"); fail("should have thrown");
} }
catch (Throwable e) { catch (Throwable e) {