HHH-6054 improve error checking
This commit is contained in:
parent
8af548b52d
commit
ea0dd35362
|
@ -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();
|
||||||
collector.addFilterDefinition(
|
BasicType<Object> tenantIdType =
|
||||||
new FilterDefinition(
|
collector.getTypeConfiguration().getBasicTypeRegistry()
|
||||||
TenantIdGeneration.FILTER_NAME,
|
.getRegisteredType(returnedClassName);
|
||||||
"",
|
FilterDefinition filterDefinition = collector.getFilterDefinition(TenantIdGeneration.FILTER_NAME);
|
||||||
singletonMap(
|
if ( filterDefinition == null ) {
|
||||||
TenantIdGeneration.PARAMETER_NAME,
|
collector.addFilterDefinition(
|
||||||
collector.getTypeConfiguration().getBasicTypeRegistry()
|
new FilterDefinition(
|
||||||
.getRegisteredType(returnedClassName)
|
TenantIdGeneration.FILTER_NAME,
|
||||||
)
|
"",
|
||||||
)
|
singletonMap( TenantIdGeneration.PARAMETER_NAME, tenantIdType )
|
||||||
);
|
)
|
||||||
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
|
||||||
|
|
|
@ -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() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {}
|
||||||
|
}
|
|
@ -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) {
|
||||||
|
|
Loading…
Reference in New Issue