initial work for table per class inheritance
This commit is contained in:
parent
2ea03f7d56
commit
47a7a0765c
|
@ -5482,8 +5482,6 @@ public abstract class AbstractEntityPersister
|
|||
return accessOptimizer.getPropertyValues( entity );
|
||||
}
|
||||
|
||||
final Collection<AttributeMapping> attributeMappings = getAttributeMappings();
|
||||
|
||||
final Object[] result = new Object[this.attributeMappings.size()];
|
||||
for ( int i = 0; i < this.attributeMappings.size(); i++ ) {
|
||||
result[i] = this.attributeMappings.get( i ).getPropertyAccess().getGetter().getForInsert(
|
||||
|
@ -6102,7 +6100,7 @@ public abstract class AbstractEntityPersister
|
|||
private List<AttributeMapping> attributeMappings;
|
||||
private List<Fetchable> staticFetchableList;
|
||||
|
||||
private ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
||||
protected ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
||||
|
||||
@Override
|
||||
public void visitAttributeMappings(Consumer<AttributeMapping> action) {
|
||||
|
@ -6142,17 +6140,7 @@ public abstract class AbstractEntityPersister
|
|||
);
|
||||
}
|
||||
|
||||
if ( getDiscriminatorType() == null && shouldProcessSuperMapping() ) {
|
||||
discriminatorMapping = null;
|
||||
}
|
||||
else {
|
||||
discriminatorMapping = new EntityDiscriminatorMappingImpl(
|
||||
this,
|
||||
getRootTableName(),
|
||||
getDiscriminatorColumnName(),
|
||||
(BasicType) getDiscriminatorType()
|
||||
);
|
||||
}
|
||||
buildDiscriminatorMapping();
|
||||
|
||||
// todo (6.0) : support for natural-id not yet implemented
|
||||
naturalIdMapping = null;
|
||||
|
@ -6165,14 +6153,13 @@ public abstract class AbstractEntityPersister
|
|||
.getEntityBinding( getEntityName() );
|
||||
|
||||
final EntityMetamodel currentEntityMetamodel = this.getEntityMetamodel();
|
||||
|
||||
int stateArrayPosition = superMappingType == null ? 0 : superMappingType.getNumberOfAttributeMappings();
|
||||
int stateArrayPosition = getStateArrayInitialPosition( creationProcess );
|
||||
|
||||
for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) {
|
||||
final NonIdentifierAttribute runtimeAttrDefinition = currentEntityMetamodel.getProperties()[i];
|
||||
final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() );
|
||||
|
||||
if ( superMappingType != null && superMappingType.findAttributeMapping( bootProperty.getName() ) != null && shouldProcessSuperMapping() ) {
|
||||
if ( superMappingType != null && superMappingType.findAttributeMapping( bootProperty.getName() ) != null ) {
|
||||
// its defined on the super-type, skip it here
|
||||
}
|
||||
else {
|
||||
|
@ -6201,6 +6188,33 @@ public abstract class AbstractEntityPersister
|
|||
}
|
||||
}
|
||||
|
||||
protected int getStateArrayInitialPosition(MappingModelCreationProcess creationProcess) {
|
||||
// todo (6.0) not sure this is correct in case of SingleTable Inheritance and for Table per class when the selection is the root
|
||||
int stateArrayPosition;
|
||||
if ( superMappingType != null ) {
|
||||
( (InFlightEntityMappingType) superMappingType ).prepareMappingModel( creationProcess );
|
||||
stateArrayPosition = superMappingType.getNumberOfAttributeMappings();
|
||||
}
|
||||
else {
|
||||
stateArrayPosition = 0;
|
||||
}
|
||||
return stateArrayPosition;
|
||||
}
|
||||
|
||||
protected void buildDiscriminatorMapping() {
|
||||
if ( getDiscriminatorType() == null) {
|
||||
discriminatorMapping = null;
|
||||
}
|
||||
else {
|
||||
discriminatorMapping = new EntityDiscriminatorMappingImpl(
|
||||
this,
|
||||
getRootTableName(),
|
||||
getDiscriminatorColumnName(),
|
||||
(BasicType) getDiscriminatorType()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldProcessSuperMapping(){
|
||||
return true;
|
||||
}
|
||||
|
@ -6524,6 +6538,7 @@ public abstract class AbstractEntityPersister
|
|||
EntityMappingType treatTargetType) {
|
||||
if ( treatTargetType == null ) {
|
||||
getStaticFetchableList().forEach( fetchableConsumer );
|
||||
// staticFetchableList.forEach( fetchableConsumer );
|
||||
// EARLY EXIT!!!
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -21,9 +21,7 @@ import org.hibernate.AssertionFailure;
|
|||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.boot.model.relational.Database;
|
||||
import org.hibernate.bytecode.spi.ReflectionOptimizer;
|
||||
import org.hibernate.cache.spi.access.EntityDataAccess;
|
||||
import org.hibernate.cache.spi.access.NaturalIdDataAccess;
|
||||
import org.hibernate.cfg.Settings;
|
||||
|
@ -40,30 +38,25 @@ import org.hibernate.internal.util.collections.JoinedIterator;
|
|||
import org.hibernate.internal.util.collections.SingletonIterator;
|
||||
import org.hibernate.mapping.Column;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Subclass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.EntityDiscriminatorMappingImpl;
|
||||
import org.hibernate.metamodel.mapping.internal.InFlightEntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.StateArrayContributorMapping;
|
||||
import org.hibernate.persister.spi.PersisterCreationContext;
|
||||
import org.hibernate.property.access.spi.Setter;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
|
||||
import org.hibernate.sql.SelectFragment;
|
||||
import org.hibernate.sql.SimpleSelect;
|
||||
import org.hibernate.sql.ast.JoinType;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBase;
|
||||
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
|
||||
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.UnionTableGroup;
|
||||
import org.hibernate.sql.ast.tree.predicate.Predicate;
|
||||
import org.hibernate.tuple.NonIdentifierAttribute;
|
||||
import org.hibernate.tuple.entity.EntityMetamodel;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.StandardBasicTypes;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
|
||||
|
||||
/**
|
||||
* Implementation of the "table-per-concrete-class" or "roll-down" mapping
|
||||
|
@ -232,9 +225,30 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
initSubclassPropertyAliasesMap( persistentClass );
|
||||
|
||||
postConstruct( creationContext.getMetadata() );
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroup createRootTableGroup(
|
||||
NavigablePath navigablePath,
|
||||
String explicitSourceAlias,
|
||||
JoinType tableReferenceJoinType,
|
||||
LockMode lockMode,
|
||||
SqlAliasBaseGenerator aliasBaseGenerator,
|
||||
SqlExpressionResolver sqlExpressionResolver,
|
||||
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
|
||||
SqlAstCreationContext creationContext) {
|
||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( getSqlAliasStem() );
|
||||
|
||||
final TableReference tableReference = new TableReference(
|
||||
getTableName(),
|
||||
sqlAliasBase.generateNewAlias(),
|
||||
false,
|
||||
getFactory()
|
||||
);
|
||||
return new UnionTableGroup( navigablePath, tableReference, this );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable[] getQuerySpaces() {
|
||||
return subclassSpaces;
|
||||
}
|
||||
|
@ -244,18 +258,27 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTableName() {
|
||||
return subquery;
|
||||
if ( hasSubclasses() ) {
|
||||
return subquery;
|
||||
}
|
||||
else {
|
||||
return tableName;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getDiscriminatorType() {
|
||||
return StandardBasicTypes.INTEGER;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getDiscriminatorValue() {
|
||||
return discriminatorValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDiscriminatorSQLValue() {
|
||||
return discriminatorSQLValue;
|
||||
}
|
||||
|
@ -264,10 +287,12 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return subclassClosure;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubclassForDiscriminatorValue(Object value) {
|
||||
return (String) subclassByDiscriminatorValue.get( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable[] getPropertySpaces() {
|
||||
return spaces;
|
||||
}
|
||||
|
@ -276,37 +301,40 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the SQL that selects a row by id
|
||||
*/
|
||||
protected String generateSelectString(LockMode lockMode) {
|
||||
SimpleSelect select = new SimpleSelect( getFactory().getDialect() )
|
||||
.setLockMode( lockMode )
|
||||
.setTableName( getTableName() )
|
||||
.addColumns( getIdentifierColumnNames() )
|
||||
.addColumns(
|
||||
getSubclassColumnClosure(),
|
||||
getSubclassColumnAliasClosure(),
|
||||
getSubclassColumnLazyiness()
|
||||
)
|
||||
.addColumns(
|
||||
getSubclassFormulaClosure(),
|
||||
getSubclassFormulaAliasClosure(),
|
||||
getSubclassFormulaLazyiness()
|
||||
@Override
|
||||
public void setPropertyValues(Object object, Object[] values) {
|
||||
if ( accessOptimizer != null ) {
|
||||
accessOptimizer.setPropertyValues( object, values );
|
||||
}
|
||||
else {
|
||||
if ( hasSubclasses() ) {
|
||||
visitAttributeMappings(
|
||||
attribute -> {
|
||||
final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition();
|
||||
final Object value = values[stateArrayPosition];
|
||||
if ( value != UNFETCHED_PROPERTY ) {
|
||||
final Setter setter = attribute.getPropertyAccess().getSetter();
|
||||
setter.set( object, value, getFactory() );
|
||||
}
|
||||
}
|
||||
);
|
||||
//TODO: include the rowids!!!!
|
||||
if ( hasSubclasses() ) {
|
||||
if ( isDiscriminatorFormula() ) {
|
||||
select.addColumn( getDiscriminatorFormula(), getDiscriminatorAlias() );
|
||||
}
|
||||
else {
|
||||
select.addColumn( getDiscriminatorColumnName(), getDiscriminatorAlias() );
|
||||
visitFetchables(
|
||||
fetchable -> {
|
||||
final AttributeMapping attribute = (AttributeMapping) fetchable;
|
||||
final int stateArrayPosition = ( (StateArrayContributorMapping) attribute ).getStateArrayPosition();
|
||||
final Object value = values[stateArrayPosition];
|
||||
if ( value != UNFETCHED_PROPERTY ) {
|
||||
final Setter setter = attribute.getPropertyAccess().getSetter();
|
||||
setter.set( object, value, getFactory() );
|
||||
}
|
||||
|
||||
},
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
if ( getFactory().getSettings().isCommentsEnabled() ) {
|
||||
select.setComment( "load " + getEntityName() );
|
||||
}
|
||||
return select.addCondition( getIdentifierColumnNames(), "=?" ).toStatementString();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -318,24 +346,29 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getTableName(int j) {
|
||||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getKeyColumns(int j) {
|
||||
return getIdentifierColumnNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isTableCascadeDeleteEnabled(int j) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isPropertyOfTable(int property, int j) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Execute the SQL:
|
||||
|
||||
@Override
|
||||
public String fromTableFragment(String name) {
|
||||
return getTableName() + ' ' + name;
|
||||
}
|
||||
|
@ -352,39 +385,55 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return filterFragment( alias );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubclassPropertyTableName(int i) {
|
||||
return getTableName();//ie. the subquery! yuck!
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addDiscriminatorToSelect(SelectFragment select, String name, String suffix) {
|
||||
select.addColumn( name, getDiscriminatorColumnName(), getDiscriminatorAlias() );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] getPropertyTableNumbersInSelect() {
|
||||
return new int[getPropertySpan()];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int getSubclassPropertyTableNumber(int i) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSubclassPropertyTableNumber(String propertyName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMultiTable() {
|
||||
// This could also just be true all the time...
|
||||
return isAbstract() || hasSubclasses();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildDiscriminatorMapping() {
|
||||
if ( hasSubclasses() ) {
|
||||
super.buildDiscriminatorMapping();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTableSpan() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] getSubclassColumnTableNumberClosure() {
|
||||
return new int[getSubclassColumnClosure().length];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] getSubclassFormulaTableNumberClosure() {
|
||||
return new int[getSubclassFormulaClosure().length];
|
||||
}
|
||||
|
@ -393,6 +442,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return new boolean[] {true};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int[] getPropertyTableNumbers() {
|
||||
return new int[getPropertySpan()];
|
||||
}
|
||||
|
@ -472,6 +522,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return buf.append( " )" ).toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String[] getSubclassTableKeyColumns(int j) {
|
||||
if ( j != 0 ) {
|
||||
throw new AssertionFailure( "only one table" );
|
||||
|
@ -479,6 +530,7 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return getIdentifierColumnNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSubclassTableName(int j) {
|
||||
if ( j != 0 ) {
|
||||
throw new AssertionFailure( "only one table" );
|
||||
|
@ -486,10 +538,12 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return tableName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSubclassTableSpan() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isClassOrSuperclassTable(int j) {
|
||||
if ( j != 0 ) {
|
||||
throw new AssertionFailure( "only one table" );
|
||||
|
@ -503,10 +557,12 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
return getTableName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getConstraintOrderedTableNameClosure() {
|
||||
return constraintOrderedTableNames;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[][] getContraintOrderedTableKeyColumnClosure() {
|
||||
return constraintOrderedKeyColumnNames;
|
||||
}
|
||||
|
@ -515,5 +571,4 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
|
|||
public FilterAliasGenerator getFilterAliasGenerator(String rootAlias) {
|
||||
return new StaticFilterAliasGenerator( rootAlias );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* 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.sql.ast.tree.from;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
public class UnionTableGroup implements VirtualTableGroup {
|
||||
private final NavigablePath navigablePath;
|
||||
|
||||
private final UnionSubclassEntityPersister modelPart;
|
||||
private final TableReference tableReference;
|
||||
|
||||
public UnionTableGroup(
|
||||
NavigablePath navigablePath,
|
||||
TableReference tableReference,
|
||||
UnionSubclassEntityPersister modelPart) {
|
||||
this.navigablePath = navigablePath;
|
||||
this.tableReference = tableReference;
|
||||
this.modelPart = modelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NavigablePath getNavigablePath() {
|
||||
return navigablePath;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getGroupAlias() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ModelPartContainer getModelPart() {
|
||||
return modelPart;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockMode getLockMode() {
|
||||
return LockMode.NONE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<TableGroupJoin> getTableGroupJoins() {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTableGroupJoins() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTableGroupJoins(Set<TableGroupJoin> joins) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTableGroupJoin(TableGroupJoin join) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void applyAffectedTableNames(Consumer<String> nameCollector) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference getPrimaryTableReference() {
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<TableReferenceJoin> getTableReferenceJoins() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInnerJoinPossible() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(
|
||||
String tableExpression, Supplier<TableReference> creator) {
|
||||
return tableReference;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(String tableExpression) {
|
||||
return tableReference;
|
||||
}
|
||||
}
|
|
@ -16,7 +16,6 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.FailureExpected;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
|
@ -36,17 +35,17 @@ import static org.hamcrest.MatcherAssert.assertThat;
|
|||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
TablePerClassInheritanceTest.Customer.class,
|
||||
TablePerClassInheritanceTest.DomesticCustomer.class,
|
||||
TablePerClassInheritanceTest.ForeignCustomer.class
|
||||
TablePerClassInheritanceWithAbstractRootTest.Customer.class,
|
||||
TablePerClassInheritanceWithAbstractRootTest.DomesticCustomer.class,
|
||||
TablePerClassInheritanceWithAbstractRootTest.ForeignCustomer.class
|
||||
}
|
||||
)
|
||||
@ServiceRegistry
|
||||
@SessionFactory
|
||||
@Tags({
|
||||
@Tag("RunnableIdeTest"),
|
||||
@Tag("RunnableIdeTest"),
|
||||
})
|
||||
public class TablePerClassInheritanceTest {
|
||||
public class TablePerClassInheritanceWithAbstractRootTest {
|
||||
|
||||
@Test
|
||||
public void basicTest(SessionFactoryScope scope) {
|
||||
|
@ -80,7 +79,6 @@ public class TablePerClassInheritanceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected
|
||||
public void rootQueryExecutionTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -114,7 +112,6 @@ public class TablePerClassInheritanceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@FailureExpected
|
||||
public void subclassQueryExecutionTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -145,7 +142,7 @@ public class TablePerClassInheritanceTest {
|
|||
);
|
||||
}
|
||||
|
||||
// @BeforeEach
|
||||
@BeforeEach
|
||||
public void createTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
|
@ -155,7 +152,7 @@ public class TablePerClassInheritanceTest {
|
|||
);
|
||||
}
|
||||
|
||||
// @AfterEach
|
||||
@AfterEach
|
||||
public void cleanupTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
|
@ -0,0 +1,240 @@
|
|||
/*
|
||||
* 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.orm.test.metamodel.mapping;
|
||||
|
||||
import java.util.List;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Inheritance;
|
||||
import javax.persistence.InheritanceType;
|
||||
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.UnionSubclassEntityPersister;
|
||||
|
||||
import org.hibernate.testing.orm.junit.DomainModel;
|
||||
import org.hibernate.testing.orm.junit.ServiceRegistry;
|
||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.instanceOf;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Andrea Boriero
|
||||
*/
|
||||
@DomainModel(
|
||||
annotatedClasses = {
|
||||
TablePerClassInheritanceWithConcreteRootTest.Customer.class,
|
||||
TablePerClassInheritanceWithConcreteRootTest.DomesticCustomer.class,
|
||||
TablePerClassInheritanceWithConcreteRootTest.ForeignCustomer.class
|
||||
}
|
||||
)
|
||||
@ServiceRegistry
|
||||
@SessionFactory
|
||||
public class TablePerClassInheritanceWithConcreteRootTest {
|
||||
|
||||
@Test
|
||||
public void basicTest(SessionFactoryScope scope) {
|
||||
final EntityPersister customerDescriptor = scope.getSessionFactory()
|
||||
.getMetamodel()
|
||||
.findEntityDescriptor( Customer.class );
|
||||
final EntityPersister domesticCustomerDescriptor = scope.getSessionFactory()
|
||||
.getMetamodel()
|
||||
.findEntityDescriptor( DomesticCustomer.class );
|
||||
final EntityPersister foreignCustomerDescriptor = scope.getSessionFactory()
|
||||
.getMetamodel()
|
||||
.findEntityDescriptor( ForeignCustomer.class );
|
||||
|
||||
assert customerDescriptor instanceof UnionSubclassEntityPersister;
|
||||
|
||||
assert customerDescriptor.isTypeOrSuperType( customerDescriptor );
|
||||
assert !customerDescriptor.isTypeOrSuperType( domesticCustomerDescriptor );
|
||||
assert !customerDescriptor.isTypeOrSuperType( foreignCustomerDescriptor );
|
||||
|
||||
assert domesticCustomerDescriptor instanceof UnionSubclassEntityPersister;
|
||||
|
||||
assert domesticCustomerDescriptor.isTypeOrSuperType( customerDescriptor );
|
||||
assert domesticCustomerDescriptor.isTypeOrSuperType( domesticCustomerDescriptor );
|
||||
assert !domesticCustomerDescriptor.isTypeOrSuperType( foreignCustomerDescriptor );
|
||||
|
||||
assert foreignCustomerDescriptor instanceof UnionSubclassEntityPersister;
|
||||
|
||||
assert foreignCustomerDescriptor.isTypeOrSuperType( customerDescriptor );
|
||||
assert !foreignCustomerDescriptor.isTypeOrSuperType( domesticCustomerDescriptor );
|
||||
assert foreignCustomerDescriptor.isTypeOrSuperType( foreignCustomerDescriptor );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rootQueryExecutionTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
{
|
||||
// [name, taxId, vat]
|
||||
final List<Customer> results = session.createQuery(
|
||||
"select c from Customer c",
|
||||
Customer.class
|
||||
).list();
|
||||
|
||||
assertThat( results.size(), is( 3 ) );
|
||||
|
||||
for ( Customer result : results ) {
|
||||
if ( result.getId() == 1 ) {
|
||||
assertThat( result, instanceOf( DomesticCustomer.class ) );
|
||||
final DomesticCustomer customer = (DomesticCustomer) result;
|
||||
assertThat( customer.getName(), is( "domestic" ) );
|
||||
assertThat( ( customer ).getTaxId(), is( "123" ) );
|
||||
}
|
||||
else if ( result.getId() == 2 ) {
|
||||
assertThat( result.getId(), is( 2 ) );
|
||||
final ForeignCustomer customer = (ForeignCustomer) result;
|
||||
assertThat( customer.getName(), is( "foreign" ) );
|
||||
assertThat( ( customer ).getVat(), is( "987" ) );
|
||||
}
|
||||
else {
|
||||
assertThat( result.getId(), is( 3 ) );
|
||||
final Customer customer = result;
|
||||
assertThat( customer.getName(), is( "customer" ) );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void subclassQueryExecutionTest(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
{
|
||||
final DomesticCustomer result = session.createQuery(
|
||||
"select c from DomesticCustomer c",
|
||||
DomesticCustomer.class
|
||||
).uniqueResult();
|
||||
|
||||
assertThat( result, notNullValue() );
|
||||
assertThat( result.getId(), is( 1 ) );
|
||||
assertThat( result.getName(), is( "domestic" ) );
|
||||
assertThat( result.getTaxId(), is( "123" ) );
|
||||
}
|
||||
|
||||
{
|
||||
final ForeignCustomer result = session.createQuery(
|
||||
"select c from ForeignCustomer c",
|
||||
ForeignCustomer.class
|
||||
).uniqueResult();
|
||||
|
||||
assertThat( result, notNullValue() );
|
||||
assertThat( result.getId(), is( 2 ) );
|
||||
assertThat( result.getName(), is( "foreign" ) );
|
||||
assertThat( result.getVat(), is( "987" ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@BeforeEach
|
||||
public void createTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.persist( new Customer( 3, "customer" ) );
|
||||
session.persist( new DomesticCustomer( 1, "domestic", "123" ) );
|
||||
session.persist( new ForeignCustomer( 2, "foreign", "987" ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
public void cleanupTestData(SessionFactoryScope scope) {
|
||||
scope.inTransaction(
|
||||
session -> {
|
||||
session.createQuery( "from Customer", Customer.class ).list().forEach(
|
||||
cust -> session.delete( cust )
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Entity(name = "Customer")
|
||||
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
|
||||
public static class Customer {
|
||||
private Integer id;
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(Integer id, String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Id
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "DomesticCustomer")
|
||||
public static class DomesticCustomer extends Customer {
|
||||
private String taxId;
|
||||
|
||||
public DomesticCustomer() {
|
||||
}
|
||||
|
||||
public DomesticCustomer(Integer id, String name, String taxId) {
|
||||
super( id, name );
|
||||
this.taxId = taxId;
|
||||
}
|
||||
|
||||
public String getTaxId() {
|
||||
return taxId;
|
||||
}
|
||||
|
||||
public void setTaxId(String taxId) {
|
||||
this.taxId = taxId;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "ForeignCustomer")
|
||||
public static class ForeignCustomer extends Customer {
|
||||
private String vat;
|
||||
|
||||
public ForeignCustomer() {
|
||||
}
|
||||
|
||||
public ForeignCustomer(Integer id, String name, String vat) {
|
||||
super( id, name );
|
||||
this.vat = vat;
|
||||
}
|
||||
|
||||
public String getVat() {
|
||||
return vat;
|
||||
}
|
||||
|
||||
public void setVat(String vat) {
|
||||
this.vat = vat;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue