HHH-14526 tolerate dupe tables in JOINED inheritance with discriminator

and also support @DiscriminatorOptions for JOINED inheritance
This commit is contained in:
Gavin 2022-12-24 04:05:04 +01:00 committed by Gavin King
parent 4946e8ca45
commit 2355f98586
24 changed files with 718 additions and 609 deletions

View File

@ -63,11 +63,7 @@ public class InformixSqmToSqlAstConverter<T extends Statement> extends BaseSqmTo
null,
null,
null,
new NamedTableReference(
"(select 1)",
"dummy_(x)",
false
),
new NamedTableReference( "(select 1)", "dummy_(x)" ),
null,
getCreationContext().getSessionFactory()
)

View File

@ -63,11 +63,7 @@ public class IngresSqmToSqlAstConverter<T extends Statement> extends BaseSqmToSq
null,
null,
null,
new NamedTableReference(
"(select 1)",
"dummy_(x)",
false
),
new NamedTableReference( "(select 1)", "dummy_(x)" ),
null,
getCreationContext().getSessionFactory()
)

View File

@ -63,7 +63,7 @@ public class SybaseLegacySqmToSqlAstConverter<T extends Statement> extends BaseS
null,
null,
null,
new NamedTableReference( "(select 1)", "dummy_(x)", false ),
new NamedTableReference( "(select 1)", "dummy_(x)" ),
null,
getCreationContext().getSessionFactory()
)

View File

@ -19,7 +19,7 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME;
*
* @author Hardy Ferentschik
*/
@Target({ TYPE })
@Target(TYPE)
@Retention(RUNTIME)
public @interface DiscriminatorOptions {
/**
@ -29,8 +29,8 @@ public @interface DiscriminatorOptions {
* there are discriminator column values which do <em>not</em>
* map to any subtype of the root entity type.
*
* @return {@code true} if allowd discriminator values must always
* by explicitly enumerated
* @return {@code true} if allowed discriminator values must always
* be explicitly enumerated
*/
boolean force() default false;

View File

@ -1886,13 +1886,13 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
}
/**
* Recursively builds a list of FkSecondPass instances ready to be processed in this order.
* Recursively builds a list of {@link FkSecondPass} instances ready to be processed in this order.
* Checking all dependencies recursively seems quite expensive, but the original code just relied
* on some sort of table name sorting which failed in certain circumstances.
* <p>
* See {@code ANN-722} and {@code ANN-730}
*
* @param orderedFkSecondPasses The list containing the <code>FkSecondPass</code> instances ready
* @param orderedFkSecondPasses The list containing the {@link FkSecondPass} instances ready
* for processing.
* @param isADependencyOf Our lookup data structure to determine dependencies between tables
* @param startTable Table name to start recursive algorithm.
@ -1905,15 +1905,13 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
String currentTable) {
Set<FkSecondPass> dependencies = isADependencyOf.get( currentTable );
if ( dependencies != null ) {
for ( FkSecondPass sp : dependencies ) {
String dependentTable = sp.getValue().getTable().getQualifiedTableName().render();
if ( dependentTable.compareTo( startTable ) == 0 ) {
throw new AnnotationException( "Circular foreign key dependency involving tables '"
+ startTable + "' and '" + dependentTable + "'" );
for ( FkSecondPass pass : dependencies ) {
String dependentTable = pass.getValue().getTable().getQualifiedTableName().render();
if ( dependentTable.compareTo( startTable ) != 0 ) {
buildRecursiveOrderedFkSecondPasses( orderedFkSecondPasses, isADependencyOf, startTable, dependentTable );
}
buildRecursiveOrderedFkSecondPasses( orderedFkSecondPasses, isADependencyOf, startTable, dependentTable );
if ( !orderedFkSecondPasses.contains( sp ) ) {
orderedFkSecondPasses.add( 0, sp );
if ( !orderedFkSecondPasses.contains( pass ) ) {
orderedFkSecondPasses.add( 0, pass );
}
}
}

View File

@ -638,6 +638,7 @@ public class EntityBinder {
}
private void singleTableInheritance(InheritanceState inheritanceState, PropertyHolder holder) {
processDiscriminatorOptions();
final AnnotatedDiscriminatorColumn discriminatorColumn = processSingleTableDiscriminatorProperties( inheritanceState );
if ( !inheritanceState.hasParents() ) { // todo : sucks that this is separate from RootClass distinction
if ( inheritanceState.hasSiblings()
@ -648,10 +649,12 @@ public class EntityBinder {
}
private void joinedInheritance(InheritanceState state, PersistentClass superEntity, PropertyHolder holder) {
processDiscriminatorOptions();
if ( state.hasParents() ) {
final AnnotatedJoinColumns joinColumns = subclassJoinColumns( annotatedClass, superEntity, context );
final JoinedSubclass jsc = (JoinedSubclass) persistentClass;
final DependantValue key = new DependantValue(context, jsc.getTable(), jsc.getIdentifier() );
final DependantValue key = new DependantValue( context, jsc.getTable(), jsc.getIdentifier() );
jsc.setKey( key );
handleForeignKeys( annotatedClass, context, key );
final OnDelete onDelete = annotatedClass.getAnnotation( OnDelete.class );
@ -753,6 +756,14 @@ public class EntityBinder {
}
}
private void processDiscriminatorOptions() {
final DiscriminatorOptions discriminatorOptions = annotatedClass.getAnnotation( DiscriminatorOptions.class );
if ( discriminatorOptions != null ) {
forceDiscriminator = discriminatorOptions.force();
insertableDiscriminator = discriminatorOptions.insert();
}
}
/**
* Process all discriminator-related metadata per rules for "single table" inheritance
*/
@ -775,12 +786,6 @@ public class EntityBinder {
LOG.invalidDiscriminatorAnnotation( annotatedClass.getName() );
}
final DiscriminatorOptions discriminatorOptions = annotatedClass.getAnnotation( DiscriminatorOptions.class );
if ( discriminatorOptions != null ) {
forceDiscriminator = discriminatorOptions.force();
insertableDiscriminator = discriminatorOptions.insert();
}
return discriminator;
}

View File

@ -63,11 +63,7 @@ public class SybaseSqmToSqlAstConverter<T extends Statement> extends BaseSqmToSq
null,
null,
null,
new NamedTableReference(
"(select 1)",
"dummy_(x)",
false
),
new NamedTableReference( "(select 1)", "dummy_(x)" ),
null,
getCreationContext().getSessionFactory()
)

View File

@ -11,7 +11,6 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import org.hibernate.AssertionFailure;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.internal.FilterConfiguration;
@ -242,14 +241,13 @@ public class Subclass extends PersistentClass {
@Override
public boolean isJoinedSubclass() {
return getTable()!=getRootTable();
return getTable() != getRootTable();
}
public void createForeignKey() {
if ( !isJoinedSubclass() ) {
throw new AssertionFailure( "not a joined-subclass" );
if ( isJoinedSubclass() ) {
getKey().createForeignKeyOfEntity( getSuperclass().getEntityName() );
}
getKey().createForeignKeyOfEntity( getSuperclass().getEntityName() );
}
@Override

View File

@ -111,6 +111,7 @@ import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.internal.FilterHelper;
import org.hibernate.internal.util.LazyValue;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
@ -234,6 +235,7 @@ import org.hibernate.sql.ast.tree.expression.AliasedExpression;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.StandardTableGroup;
import org.hibernate.sql.ast.tree.from.TableGroup;
@ -241,7 +243,10 @@ import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.insert.InsertSelectStatement;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.predicate.Junction;
import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectClause;
@ -271,6 +276,7 @@ import org.hibernate.type.Type;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.java.MutabilityPlan;
import static java.util.Collections.emptySet;
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.ManagedTypeHelper.processIfPersistentAttributeInterceptable;
@ -278,7 +284,20 @@ import static org.hibernate.engine.internal.ManagedTypeHelper.processIfSelfDirti
import static org.hibernate.engine.internal.Versioning.isVersionIncrementRequired;
import static org.hibernate.generator.EventType.INSERT;
import static org.hibernate.generator.EventType.UPDATE;
import static org.hibernate.internal.util.StringHelper.isEmpty;
import static org.hibernate.internal.util.collections.ArrayHelper.contains;
import static org.hibernate.internal.util.collections.ArrayHelper.to2DStringArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toBooleanArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toIntArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toObjectArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toStringArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toTypeArray;
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
import static org.hibernate.internal.util.collections.CollectionHelper.toSmallList;
import static org.hibernate.metamodel.RepresentationMode.POJO;
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
import static org.hibernate.pretty.MessageHelper.infoString;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
/**
@ -433,6 +452,9 @@ public abstract class AbstractEntityPersister
protected ReflectionOptimizer.AccessOptimizer accessOptimizer;
private final String[] fullDiscriminatorSQLValues;
private final Object[] fullDiscriminatorValues;
/**
* Warning:
* When there are duplicated property names in the subclasses
@ -524,12 +546,10 @@ public abstract class AbstractEntityPersister
final NamedQueryMemento namedQueryMemento = factory.getQueryEngine().getNamedObjectRepository()
.resolve( factory, creationContext.getBootModel(), bootDescriptor.getLoaderName() );
if ( namedQueryMemento == null ) {
throw new IllegalArgumentException( "Could not resolve named load-query [" + getEntityName() + "] : " + bootDescriptor.getLoaderName() );
throw new IllegalArgumentException( "Could not resolve named load-query [" + getEntityName()
+ "] : " + bootDescriptor.getLoaderName() );
}
singleIdEntityLoader = new SingleIdEntityLoaderProvidedQueryImpl<>(
this,
namedQueryMemento
);
singleIdEntityLoader = new SingleIdEntityLoaderProvidedQueryImpl<>(this, namedQueryMemento );
}
else if ( batchSize > 1 ) {
singleIdEntityLoader = createBatchingIdEntityLoader( this, batchSize, factory );
@ -558,12 +578,12 @@ public abstract class AbstractEntityPersister
// VERSION
versionColumnName = bootDescriptor.isVersioned()
? bootDescriptor.getVersion().getColumns().get(0).getQuotedName(dialect)
? bootDescriptor.getVersion().getColumns().get(0).getQuotedName( dialect )
: null;
//WHERE STRING
if ( StringHelper.isEmpty( bootDescriptor.getWhere() ) ) {
if ( isEmpty( bootDescriptor.getWhere() ) ) {
sqlWhereStringTableExpression = null;
sqlWhereStringTemplate = null;
}
@ -576,7 +596,7 @@ public abstract class AbstractEntityPersister
}
containingClass = superclass;
}
this.sqlWhereStringTableExpression = determineTableName( containingClass.getTable() );
sqlWhereStringTableExpression = determineTableName( containingClass.getTable() );
sqlWhereStringTemplate = Template.renderWhereStringTemplate(
"(" + bootDescriptor.getWhere() + ")",
dialect,
@ -670,12 +690,12 @@ public abstract class AbstractEntityPersister
lobPropertiesLocalCollector.add( i );
}
}
this.lobProperties = CollectionHelper.toSmallList( lobPropertiesLocalCollector );
lobProperties = toSmallList( lobPropertiesLocalCollector );
hasFormulaProperties = foundFormula;
lazyPropertyColumnAliases = ArrayHelper.to2DStringArray( lazyColAliases );
lazyPropertyNames = ArrayHelper.toStringArray( lazyNames );
lazyPropertyNumbers = ArrayHelper.toIntArray( lazyNumbers );
lazyPropertyTypes = ArrayHelper.toTypeArray( lazyTypes );
lazyPropertyColumnAliases = to2DStringArray( lazyColAliases );
lazyPropertyNames = toStringArray( lazyNames );
lazyPropertyNumbers = toIntArray( lazyNumbers );
lazyPropertyTypes = toTypeArray( lazyTypes );
// SUBCLASS PROPERTY CLOSURE
final ArrayList<String> aliases = new ArrayList<>();
@ -744,16 +764,16 @@ public abstract class AbstractEntityPersister
joinedFetchesList.add( prop.getValue().getFetchMode() );
cascades.add( prop.getCascadeStyle() );
}
subclassColumnAliasClosure = ArrayHelper.toStringArray( aliases );
subclassFormulaAliasClosure = ArrayHelper.toStringArray( formulaAliases );
subclassColumnAliasClosure = toStringArray( aliases );
subclassFormulaAliasClosure = toStringArray( formulaAliases );
subclassPropertyNameClosure = ArrayHelper.toStringArray( names );
subclassPropertyTypeClosure = ArrayHelper.toTypeArray( types );
subclassPropertyNullabilityClosure = ArrayHelper.toBooleanArray( propNullables );
subclassPropertyFormulaTemplateClosure = ArrayHelper.to2DStringArray( templates );
subclassPropertyColumnNameClosure = ArrayHelper.to2DStringArray( propColumns );
subclassPropertyColumnReaderClosure = ArrayHelper.to2DStringArray( propColumnReaders );
subclassPropertyColumnReaderTemplateClosure = ArrayHelper.to2DStringArray( propColumnReaderTemplates );
subclassPropertyNameClosure = toStringArray( names );
subclassPropertyTypeClosure = toTypeArray( types );
subclassPropertyNullabilityClosure = toBooleanArray( propNullables );
subclassPropertyFormulaTemplateClosure = to2DStringArray( templates );
subclassPropertyColumnNameClosure = to2DStringArray( propColumns );
subclassPropertyColumnReaderClosure = to2DStringArray( propColumnReaders );
subclassPropertyColumnReaderTemplateClosure = to2DStringArray( propColumnReaderTemplates );
subclassPropertyCascadeStyleClosure = new CascadeStyle[cascades.size()];
int j = 0;
@ -766,19 +786,48 @@ public abstract class AbstractEntityPersister
subclassPropertyFetchModeClosure[j++] = fetchMode;
}
propertyDefinedOnSubclass = ArrayHelper.toBooleanArray( definedBySubclass );
propertyDefinedOnSubclass = toBooleanArray( definedBySubclass );
// Handle any filters applied to the class level
filterHelper = CollectionHelper.isNotEmpty( bootDescriptor.getFilters() )
? new FilterHelper(bootDescriptor.getFilters(), factory)
filterHelper = isNotEmpty( bootDescriptor.getFilters() )
? new FilterHelper( bootDescriptor.getFilters(), factory )
: null;
useReferenceCacheEntries = shouldUseReferenceCacheEntries();
cacheEntryHelper = buildCacheEntryHelper();
invalidateCache = sessionFactoryOptions.isSecondLevelCacheEnabled()
&& canWriteToCache
&& shouldInvalidateCache(bootDescriptor, creationContext);
&& shouldInvalidateCache( bootDescriptor, creationContext );
final List<Object> values = new ArrayList<>();
final List<String> sqlValues = new ArrayList<>();
if ( bootDescriptor.isPolymorphic() && bootDescriptor.getDiscriminator() != null ) {
if ( !getEntityMetamodel().isAbstract() ) {
Object discriminatorValue = DiscriminatorHelper.getDiscriminatorValue( bootDescriptor );
String discriminatorSQLValue = DiscriminatorHelper.getDiscriminatorSQLValue( bootDescriptor, dialect, factory );
values.add( discriminatorValue );
sqlValues.add( discriminatorSQLValue );
}
final List<Subclass> subclasses = bootDescriptor.getSubclasses();
for ( int k = 0; k < subclasses.size(); k++ ) {
Subclass subclass = subclasses.get( k );
//copy/paste from EntityMetamodel:
boolean subclassAbstract = subclass.isAbstract() == null
? subclass.hasPojoRepresentation() && ReflectHelper.isAbstractClass( subclass.getMappedClass() )
: subclass.isAbstract();
if ( !subclassAbstract ) {
Object subclassDiscriminatorValue = DiscriminatorHelper.getDiscriminatorValue( subclass );
values.add( subclassDiscriminatorValue );
sqlValues.add( DiscriminatorHelper.getDiscriminatorSQLValue( subclass, dialect, factory ) );
}
}
}
fullDiscriminatorSQLValues = toStringArray( sqlValues );
fullDiscriminatorValues = toObjectArray( values );
}
private boolean shouldUseReferenceCacheEntries() {
@ -815,20 +864,18 @@ public abstract class AbstractEntityPersister
protected abstract boolean isClassOrSuperclassTable(int j);
protected boolean isClassOrSuperclassJoin(int j) {
/*
* TODO:
* SingleTableEntityPersister incorrectly used isClassOrSuperclassJoin == isClassOrSuperclassTable,
* this caused HHH-12895, as this resulted in the subclass tables always being joined, even if no
* property on these tables was accessed.
*
* JoinedTableEntityPersister does not use isClassOrSuperclassJoin at all, probably incorrectly so.
* I however haven't been able to reproduce any quirks regarding <join>s, secondary tables or
* @JoinTable's.
*
* Probably this method needs to be properly implemented for the various entity persisters,
* but this at least fixes the SingleTableEntityPersister, while maintaining the previous
* behaviour for other persisters.
*/
// TODO:
// SingleTableEntityPersister incorrectly used isClassOrSuperclassJoin == isClassOrSuperclassTable,
// this caused HHH-12895, as this resulted in the subclass tables always being joined, even if no
// property on these tables was accessed.
//
// JoinedTableEntityPersister does not use isClassOrSuperclassJoin at all, probably incorrectly so.
// I however haven't been able to reproduce any quirks regarding <join>s, secondary tables or
// @JoinTable's.
//
// Probably this method needs to be properly implemented for the various entity persisters,
// but this at least fixes the SingleTableEntityPersister, while maintaining the previous
// behaviour for other persisters.
return isClassOrSuperclassTable( j );
}
@ -956,9 +1003,6 @@ public abstract class AbstractEntityPersister
return tableNames;
}
private static SingleIdEntityLoader<?> createBatchingIdEntityLoader(
EntityMappingType entityDescriptor,
int batchSize,
@ -989,7 +1033,7 @@ public abstract class AbstractEntityPersister
// there is a risk of concurrent updates
return true;
}
else if ( isCacheComplianceEnabled(creationContext) ) {
else if ( isCacheComplianceEnabled( creationContext ) ) {
// The JPA TCK (inadvertently, but still...)
// requires that we cache entities with secondary
// tables instead of being more careful and just
@ -1066,9 +1110,8 @@ public abstract class AbstractEntityPersister
final LazyAttributesMetadata lazyAttributesMetadata = enhancementMetadata.getLazyAttributesMetadata();
for ( String groupName : lazyAttributesMetadata.getFetchGroupNames() ) {
final List<LazyAttributeDescriptor> fetchGroupAttributeDescriptors = lazyAttributesMetadata.getFetchGroupAttributeDescriptors(
groupName
);
final List<LazyAttributeDescriptor> fetchGroupAttributeDescriptors =
lazyAttributesMetadata.getFetchGroupAttributeDescriptors( groupName );
final List<ModelPart> partsToSelect = new ArrayList<>( fetchGroupAttributeDescriptors.size() );
for ( LazyAttributeDescriptor lazyAttributeDescriptor : fetchGroupAttributeDescriptors ) {
@ -1186,68 +1229,12 @@ public abstract class AbstractEntityPersister
return naturalIdMapping;
}
@Override
public TableGroup createRootTableGroup(
boolean canUseInnerJoins,
NavigablePath navigablePath,
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlExpressionResolver sqlExpressionResolver,
FromClauseAccess fromClauseAccess,
SqlAstCreationContext creationContext) {
final TableReference primaryTableReference = createPrimaryTableReference(
sqlAliasBase,
sqlExpressionResolver,
creationContext
);
return new StandardTableGroup(
canUseInnerJoins,
navigablePath,
this,
explicitSourceAlias,
primaryTableReference,
true,
sqlAliasBase,
(tableExpression) -> ArrayHelper.contains( getSubclassTableNames(), tableExpression ),
(tableExpression, tg) -> {
final String[] subclassTableNames = getSubclassTableNames();
for ( int i = 0; i < subclassTableNames.length; i++ ) {
if ( tableExpression.equals( subclassTableNames[ i ] ) ) {
final NamedTableReference joinedTableReference = new NamedTableReference(
tableExpression,
sqlAliasBase.generateNewAlias(),
isNullableSubclassTable( i )
);
return new TableReferenceJoin(
shouldInnerJoinSubclassTable( i, Collections.emptySet() ),
joinedTableReference,
additionalPredicateCollectorAccess == null
? null
: generateJoinPredicate(
primaryTableReference,
joinedTableReference,
getSubclassTableKeyColumns( i ),
sqlExpressionResolver
)
);
}
}
return null;
},
getFactory()
);
}
@Override
public TableReference createPrimaryTableReference(
SqlAliasBase sqlAliasBase,
SqlExpressionResolver sqlExpressionResolver,
SqlAstCreationContext creationContext) {
return resolvePrimaryTableReference( sqlAliasBase );
return new NamedTableReference( getTableName(), sqlAliasBase.generateNewAlias() );
}
@ -1265,7 +1252,7 @@ public abstract class AbstractEntityPersister
lhs,
joinTableExpression,
sqlAliasBase,
shouldInnerJoinSubclassTable( i, Collections.emptySet() ),
shouldInnerJoinSubclassTable( i, emptySet() ),
getSubclassTableKeyColumns( i ),
sqlExpressionResolver
);
@ -1294,37 +1281,29 @@ public abstract class AbstractEntityPersister
generateJoinPredicate(
lhs,
joinedTableReference,
getKeyColumnNames(),
targetColumns,
sqlExpressionResolver
)
);
}
protected TableReference resolvePrimaryTableReference(SqlAliasBase sqlAliasBase) {
return new NamedTableReference(
getTableName(),
sqlAliasBase.generateNewAlias(),
false
);
}
protected Predicate generateJoinPredicate(
TableReference rootTableReference,
TableReference joinedTableReference,
String[] pkColumnNames,
String[] fkColumnNames,
SqlExpressionResolver sqlExpressionResolver) {
final EntityIdentifierMapping identifierMapping = getIdentifierMapping();
final Junction conjunction = new Junction( Junction.Nature.CONJUNCTION );
final String[] rootPkColumnNames = getKeyColumnNames();
assert rootPkColumnNames.length == fkColumnNames.length;
assert rootPkColumnNames.length == identifierMapping.getJdbcTypeCount();
assert pkColumnNames.length == fkColumnNames.length;
assert pkColumnNames.length == identifierMapping.getJdbcTypeCount();
identifierMapping.forEachSelectable(
(columnIndex, selection) -> {
final String rootPkColumnName = rootPkColumnNames[ columnIndex ];
final String rootPkColumnName = pkColumnNames[ columnIndex ];
final Expression pkColumnExpression = sqlExpressionResolver.resolveSqlExpression(
createColumnReferenceKey( rootTableReference, rootPkColumnName ),
sqlAstProcessingState -> new ColumnReference(
@ -1424,11 +1403,9 @@ public abstract class AbstractEntityPersister
if ( LOG.isTraceEnabled() ) {
LOG.tracev(
"Initializing lazy properties of: {0}, field access: {1}", MessageHelper.infoString(
this,
id,
getFactory()
), fieldName
"Initializing lazy properties of: {0}, field access: {1}",
infoString( this, id, getFactory() ),
fieldName
);
}
@ -1465,12 +1442,13 @@ public abstract class AbstractEntityPersister
return collectionType.getKeyOfOwner( owner, session );
}
final EntityPersister ownerPersister = persister.getOwnerEntityPersister();
if ( collectionType.getLHSPropertyName() == null ) {
// collection key is defined by the owning entity identifier
return persister.getOwnerEntityPersister().getIdentifier( owner, session );
return ownerPersister.getIdentifier( owner, session );
}
else {
return persister.getOwnerEntityPersister().getPropertyValue( owner, collectionType.getLHSPropertyName() );
return ownerPersister.getPropertyValue( owner, collectionType.getLHSPropertyName() );
}
}
@ -1525,7 +1503,6 @@ public abstract class AbstractEntityPersister
}
final Object selectedValue = values[i++];
final boolean set = initializeLazyProperty(
fieldName,
entity,
@ -1544,10 +1521,10 @@ public abstract class AbstractEntityPersister
return result;
}
catch (JDBCException ex) {
catch ( JDBCException ex ) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
ex.getSQLException(),
"could not initialize lazy properties: " + MessageHelper.infoString( this, id, getFactory() ),
"could not initialize lazy properties: " + infoString( this, id, getFactory() ),
lazySelect.getJdbcSelect().getSqlString()
);
}
@ -1575,11 +1552,7 @@ public abstract class AbstractEntityPersister
// don't try to initialize the unfetched property
}
else {
final Object propValue = lazyPropertyType.assemble(
cachedValue,
session,
entity
);
final Object propValue = lazyPropertyType.assemble( cachedValue, session, entity );
if ( initializeLazyProperty( fieldName, entity, entry, j, propValue ) ) {
result = propValue;
}
@ -1954,7 +1927,7 @@ public abstract class AbstractEntityPersister
);
if ( LOG.isTraceEnabled() ) {
LOG.trace(
"Forcing version increment [" + MessageHelper.infoString( this, id, getFactory() ) + "; "
"Forcing version increment [" + infoString( this, id, getFactory() ) + "; "
+ getVersionType().toLoggableString( currentVersion, getFactory() ) + " -> "
+ getVersionType().toLoggableString( nextVersion, getFactory() ) + "]"
);
@ -2014,7 +1987,7 @@ public abstract class AbstractEntityPersister
public Object getCurrentVersion(Object id, SharedSessionContractImplementor session) throws HibernateException {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Getting version: {0}", MessageHelper.infoString( this, id, getFactory() ) );
LOG.tracev( "Getting version: {0}", infoString( this, id, getFactory() ) );
}
try {
@ -2046,7 +2019,7 @@ public abstract class AbstractEntityPersister
catch (SQLException e) {
throw session.getJdbcServices().getSqlExceptionHelper().convert(
e,
"could not retrieve version: " + MessageHelper.infoString( this, id, getFactory() ),
"could not retrieve version: " + infoString( this, id, getFactory() ),
getVersionSelectString()
);
}
@ -2238,11 +2211,11 @@ public abstract class AbstractEntityPersister
if ( tableNumber == 0 ) {
return rootAlias;
}
StringBuilder buf = new StringBuilder().append( rootAlias );
StringBuilder alias = new StringBuilder().append( rootAlias );
if ( !rootAlias.endsWith( "_" ) ) {
buf.append( '_' );
alias.append( '_' );
}
return buf.append( tableNumber ).append( '_' ).toString();
return alias.append( tableNumber ).append( '_' ).toString();
}
@Override
@ -2382,7 +2355,7 @@ public abstract class AbstractEntityPersister
}
}
return ArrayHelper.toIntArray( fields );
return toIntArray( fields );
}
@Override
@ -2442,7 +2415,7 @@ public abstract class AbstractEntityPersister
}
}
return ArrayHelper.toIntArray( fields );
return toIntArray( fields );
}
private boolean isDirty(
@ -2718,7 +2691,7 @@ public abstract class AbstractEntityPersister
catch (TooManyRowsAffectedException e) {
throw new HibernateException(
"Duplicate identifier in table for: " +
MessageHelper.infoString( this, id, getFactory() )
infoString( this, id, getFactory() )
);
}
catch (Throwable t) {
@ -2954,13 +2927,179 @@ public abstract class AbstractEntityPersister
}
}
protected abstract boolean needsDiscriminator();
protected boolean isDiscriminatorFormula() {
return false;
}
@Override
public TableGroup createRootTableGroup(
boolean canUseInnerJoins,
NavigablePath navigablePath,
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlExpressionResolver expressionResolver,
FromClauseAccess fromClauseAccess,
SqlAstCreationContext creationContext) {
final TableReference rootTableReference = new NamedTableReference(
needsDiscriminator() ? getRootTableName() : getTableName(),
sqlAliasBase.generateNewAlias()
);
final TableGroup tableGroup = new StandardTableGroup(
canUseInnerJoins,
navigablePath,
this,
explicitSourceAlias,
rootTableReference,
true,
sqlAliasBase,
(tableExpression) -> contains( getSubclassTableNames(), tableExpression ),
(tableExpression, tg) -> {
final String[] subclassTableNames = getSubclassTableNames();
for ( int i = 0; i < subclassTableNames.length; i++ ) {
if ( tableExpression.equals( subclassTableNames[ i ] ) ) {
final NamedTableReference joinedTableReference = new NamedTableReference(
tableExpression,
sqlAliasBase.generateNewAlias(),
isNullableSubclassTable( i )
);
return new TableReferenceJoin(
shouldInnerJoinSubclassTable( i, emptySet() ),
joinedTableReference,
additionalPredicateCollectorAccess == null
? null
: generateJoinPredicate(
rootTableReference,
joinedTableReference,
needsDiscriminator()
? getRootTableKeyColumnNames()
: getKeyColumnNames(),
getSubclassTableKeyColumns( i ),
expressionResolver
)
);
}
}
return null;
},
getFactory()
);
if ( additionalPredicateCollectorAccess != null && needsDiscriminator() ) {
final String alias = tableGroup.getPrimaryTableReference().getIdentificationVariable();
final Predicate discriminatorPredicate = createDiscriminatorPredicate( alias, tableGroup, expressionResolver );
additionalPredicateCollectorAccess.get().accept( discriminatorPredicate );
}
return tableGroup;
}
@Override
public void applyDiscriminator(
Consumer<Predicate> predicateConsumer,
String alias,
TableGroup tableGroup,
SqlAstCreationState creationState) {
// by default, nothing to do
if ( needsDiscriminator() ) {
predicateConsumer.accept(
createDiscriminatorPredicate(
alias,
tableGroup,
creationState.getSqlExpressionResolver()
)
);
}
}
private Predicate createDiscriminatorPredicate(
String alias,
TableGroup tableGroup,
SqlExpressionResolver sqlExpressionResolver) {
final SqlExpressionResolver.ColumnReferenceKey columnReferenceKey;
final String discriminatorExpression;
if ( isDiscriminatorFormula() ) {
discriminatorExpression = getDiscriminatorFormulaTemplate();
columnReferenceKey = createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
getDiscriminatorFormulaTemplate()
);
}
else {
discriminatorExpression = getDiscriminatorColumnName();
columnReferenceKey = createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
getDiscriminatorColumnName()
);
}
final BasicType<?> discriminatorType = (BasicType<?>) getDiscriminatorMapping().getJdbcMapping();
final Expression sqlExpression = sqlExpressionResolver.resolveSqlExpression(
columnReferenceKey,
sqlAstProcessingState -> new ColumnReference(
alias,
discriminatorExpression,
isDiscriminatorFormula(),
null,
null,
discriminatorType.getJdbcMapping()
)
);
return createDisciminatorPredicate( discriminatorType, sqlExpression );
}
private Predicate createDisciminatorPredicate(BasicType<?> discriminatorType, Expression sqlExpression) {
if ( hasSubclasses() ) {
return createInListPredicate( discriminatorType, sqlExpression );
}
else {
final Object value = getDiscriminatorValue();
if ( value == NULL_DISCRIMINATOR ) {
return new NullnessPredicate( sqlExpression );
}
else if ( value == NOT_NULL_DISCRIMINATOR ) {
return new NegatedPredicate( new NullnessPredicate( sqlExpression ) );
}
else {
final QueryLiteral<Object> literal = new QueryLiteral<>( value, discriminatorType );
return new ComparisonPredicate( sqlExpression, ComparisonOperator.EQUAL, literal );
}
}
}
private Predicate createInListPredicate(BasicType<?> discriminatorType, Expression sqlExpression) {
final List<Expression> values = new ArrayList<>( fullDiscriminatorValues.length );
boolean hasNull = false, hasNonNull = false;
for ( Object discriminatorValue : fullDiscriminatorValues ) {
if ( discriminatorValue == NULL_DISCRIMINATOR ) {
hasNull = true;
}
else if ( discriminatorValue == NOT_NULL_DISCRIMINATOR ) {
hasNonNull = true;
}
else {
values.add( new QueryLiteral<>( discriminatorValue, discriminatorType) );
}
}
final Predicate predicate = new InListPredicate( sqlExpression, values );
if ( hasNull || hasNonNull ) {
final Junction junction = new Junction( Junction.Nature.DISJUNCTION );
if ( hasNull && hasNonNull ) {
// This means we need to select everything, we don't need a predicate at all
// Return an empty Junction
return junction;
}
junction.add( new NullnessPredicate( sqlExpression ) );
junction.add( predicate );
return junction;
}
return predicate;
}
@Override
@ -2970,40 +3109,48 @@ public abstract class AbstractEntityPersister
boolean useQualifier,
Map<String, Filter> enabledFilters,
SqlAstCreationState creationState) {
if ( filterHelper == null ) {
return;
if ( filterHelper != null ) {
final FilterAliasGenerator filterAliasGenerator = useQualifier && tableGroup != null
? getFilterAliasGenerator( tableGroup )
: null;
filterHelper.applyEnabledFilters( predicateConsumer, filterAliasGenerator, enabledFilters );
}
final FilterAliasGenerator filterAliasGenerator = useQualifier && tableGroup != null
? getFilterAliasGenerator( tableGroup )
: null;
filterHelper.applyEnabledFilters( predicateConsumer, filterAliasGenerator, enabledFilters );
}
@Override
public void applyBaseRestrictions(Consumer<Predicate> predicateConsumer, TableGroup tableGroup, boolean useQualifier, Map<String, Filter> enabledFilters, Set<String> treatAsDeclarations, SqlAstCreationState creationState) {
public void applyBaseRestrictions(
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup, boolean useQualifier,
Map<String, Filter> enabledFilters,
Set<String> treatAsDeclarations,
SqlAstCreationState creationState) {
applyFilterRestrictions( predicateConsumer, tableGroup, useQualifier, enabledFilters, creationState );
applyWhereRestrictions( predicateConsumer, tableGroup, useQualifier, creationState );
}
@Override
public void applyWhereRestrictions(Consumer<Predicate> predicateConsumer, TableGroup tableGroup, boolean useQualifier, SqlAstCreationState creationState) {
public void applyWhereRestrictions(
Consumer<Predicate> predicateConsumer,
TableGroup tableGroup,
boolean useQualifier,
SqlAstCreationState creationState) {
if ( sqlWhereStringTemplate == null ) {
return;
}
final String alias;
final TableReference tableReference;
if ( tableGroup == null || ( tableReference = tableGroup.resolveTableReference( sqlWhereStringTableExpression ) ) == null ) {
if ( tableGroup == null ) {
alias = null;
}
else {
if ( useQualifier && tableReference.getIdentificationVariable() != null ) {
alias = tableReference.getIdentificationVariable();
final TableReference tableReference = tableGroup.resolveTableReference( sqlWhereStringTableExpression );
if ( tableReference == null ) {
alias = null;
}
else {
alias = tableReference.getTableId();
alias = useQualifier && tableReference.getIdentificationVariable() != null
? tableReference.getIdentificationVariable()
: tableReference.getTableId();
}
}
@ -3016,14 +3163,12 @@ public abstract class AbstractEntityPersister
return rootAlias;
}
protected boolean shouldInnerJoinSubclassTable(
int subclassTableNumber,
Set<String> treatAsDeclarations) {
protected boolean shouldInnerJoinSubclassTable(int subclassTableNumber, Set<String> treatAsDeclarations) {
if ( isClassOrSuperclassJoin( subclassTableNumber ) ) {
// the table is either this persister's driving table or (one of) its super class persister's driving
// tables which can be inner joined as long as the `shouldInnerJoin` condition resolves to true
return !isInverseTable( subclassTableNumber )
&& !isNullableTable( subclassTableNumber );
&& !isNullableTable( subclassTableNumber );
}
// otherwise we have a subclass table and need to look a little deeper...
@ -3035,9 +3180,7 @@ public abstract class AbstractEntityPersister
return isSubclassTableIndicatedByTreatAsDeclarations(subclassTableNumber, treatAsDeclarations);
}
protected boolean isSubclassTableIndicatedByTreatAsDeclarations(
int subclassTableNumber,
Set<String> treatAsDeclarations) {
protected boolean isSubclassTableIndicatedByTreatAsDeclarations(int subclassTableNumber, Set<String> treatAsDeclarations) {
return false;
}
@ -3156,7 +3299,7 @@ public abstract class AbstractEntityPersister
isOptional,
isInverse,
isIdentifierTable,
ArrayHelper.toIntArray( attributeIndexes ),
toIntArray( attributeIndexes ),
insertExpectation,
customInsertSql,
insertCallable,
@ -3346,7 +3489,7 @@ public abstract class AbstractEntityPersister
private Object doLoad(Object id, Object optionalObject, LockOptions lockOptions, Boolean readOnly, SharedSessionContractImplementor session)
throws HibernateException {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Fetching entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
LOG.tracev( "Fetching entity: {0}", infoString( this, id, getFactory() ) );
}
if ( optionalObject == null ) {
@ -4129,7 +4272,8 @@ public abstract class AbstractEntityPersister
}
}
else if ( identifierMapping instanceof NonAggregatedIdentifierMapping ) {
final EmbeddedAttributeMapping embeddedAttributeMapping = (EmbeddedAttributeMapping) findAttributeMapping( NavigableRole.IDENTIFIER_MAPPER_PROPERTY );
final EmbeddedAttributeMapping embeddedAttributeMapping =
(EmbeddedAttributeMapping) findAttributeMapping( NavigableRole.IDENTIFIER_MAPPER_PROPERTY );
final AttributeMapping mapping = embeddedAttributeMapping == null
? null
: embeddedAttributeMapping.getMappedType().findAttributeMapping( basePropertyName );
@ -4233,18 +4377,13 @@ public abstract class AbstractEntityPersister
}
// reset the identifier
setIdentifier(
entity,
identifierMapping.getUnsavedStrategy().getDefaultValue( currentId ),
session
);
final Object idDefault = identifierMapping.getUnsavedStrategy().getDefaultValue(currentId);
setIdentifier( entity, idDefault, session );
// reset the version
if ( versionMapping != null ) {
versionMapping.getVersionAttribute().getPropertyAccess().getSetter().set(
entity,
versionMapping.getUnsavedStrategy().getDefaultValue( currentVersion )
);
final Object versionDefault = versionMapping.getUnsavedStrategy().getDefaultValue(currentVersion);
versionMapping.getVersionAttribute().getPropertyAccess().getSetter().set( entity, versionDefault );
}
}
@ -4296,12 +4435,9 @@ public abstract class AbstractEntityPersister
}
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(
entity,
mergeMap,
session
);
for ( int i = 0; i < attributeMappings.size(); i++ ) {
result[i] = attributeMappings.get( i )
.getPropertyAccess().getGetter().getForInsert( entity, mergeMap, session );
}
return result;
}
@ -4325,12 +4461,7 @@ public abstract class AbstractEntityPersister
throw new UnsupportedOperationException( "Entity has no insert-generated properties - `" + getEntityName() + "`" );
}
insertGeneratedValuesProcessor.processGeneratedValues(
entity,
id,
state,
session
);
insertGeneratedValuesProcessor.processGeneratedValues( entity, id, state, session );
}
@Override
@ -4342,12 +4473,7 @@ public abstract class AbstractEntityPersister
if ( updateGeneratedValuesProcessor == null ) {
throw new AssertionFailure( "Entity has no update-generated properties - `" + getEntityName() + "`" );
}
updateGeneratedValuesProcessor.processGeneratedValues(
entity,
id,
state,
session
);
updateGeneratedValuesProcessor.processGeneratedValues( entity, id, state, session );
}
@Override
@ -4425,7 +4551,7 @@ public abstract class AbstractEntityPersister
LOG.tracef(
"Resolving natural-id [%s] to id : %s ",
Arrays.asList( naturalIdValues ),
MessageHelper.infoString( this )
infoString( this )
);
}
@ -5631,10 +5757,8 @@ public abstract class AbstractEntityPersister
private ModelPart getIdentifierModelPart(String name, EntityMappingType treatTargetType) {
if ( identifierMapping instanceof NonAggregatedIdentifierMapping ) {
final ModelPart subPart = ( (NonAggregatedIdentifierMapping) identifierMapping ).findSubPart(
name,
treatTargetType
);
NonAggregatedIdentifierMapping mapping = (NonAggregatedIdentifierMapping) identifierMapping;
final ModelPart subPart = mapping.findSubPart( name, treatTargetType );
if ( subPart != null ) {
return subPart;
}
@ -5648,15 +5772,9 @@ public abstract class AbstractEntityPersister
}
private boolean isIdentifierReference(String name) {
if ( EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name ) ) {
return true;
}
if ( hasIdentifierProperty() && getIdentifierPropertyName().equals( name ) ) {
return true;
}
return !entityMetamodel.hasNonIdentifierPropertyNamedId() && "id".equals( name );
return EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( name )
|| hasIdentifierProperty() && getIdentifierPropertyName().equals( name )
|| !entityMetamodel.hasNonIdentifierPropertyNamedId() && "id".equals( name );
}
@Override
@ -5664,7 +5782,6 @@ public abstract class AbstractEntityPersister
Consumer<ModelPart> consumer,
EntityMappingType treatTargetType) {
consumer.accept( identifierMapping );
declaredAttributeMappings.forEachValue( consumer );
}
@ -5810,12 +5927,8 @@ public abstract class AbstractEntityPersister
int offset,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
return getIdentifierMapping().forEachDisassembledJdbcValue(
value,
offset,
valuesConsumer,
session
);
return getIdentifierMapping()
.forEachDisassembledJdbcValue( value, offset, valuesConsumer, session );
}
@Override
@ -5832,12 +5945,7 @@ public abstract class AbstractEntityPersister
else {
identifier = identifierMapping.disassemble( identifierMapping.getIdentifier( value ), session );
}
return identifierMapping.forEachDisassembledJdbcValue(
identifier,
offset,
consumer,
session
);
return identifierMapping.forEachDisassembledJdbcValue( identifier, offset, consumer, session );
}
@Override
@ -6039,7 +6147,7 @@ public abstract class AbstractEntityPersister
boolean isUpdate) throws SQLException, HibernateException {
if ( LOG.isTraceEnabled() ) {
LOG.tracev( "Dehydrating entity: {0}", MessageHelper.infoString( this, id, getFactory() ) );
LOG.tracev( "Dehydrating entity: {0}", infoString( this, id, getFactory() ) );
}
for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) {

View File

@ -31,7 +31,6 @@ import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.Join;
@ -44,6 +43,7 @@ import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DiscriminatorValueDetails;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityVersionMapping;
@ -76,6 +76,10 @@ import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.jboss.logging.Logger;
import static java.util.Collections.emptyMap;
import static org.hibernate.internal.util.collections.ArrayHelper.to2DStringArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toStringArray;
import static org.hibernate.jdbc.Expectations.appropriateExpectation;
import static org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper.buildEncapsulatedCompositeIdentifierMapping;
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
@ -150,6 +154,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
private final BasicType<?> discriminatorType;
private final String explicitDiscriminatorColumnName;
private final String discriminatorAlias;
private final boolean forceDiscriminator;
// Span of the tables directly mapped by this entity and super-classes, if any
private final int coreTableSpan;
@ -190,10 +195,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
// DISCRIMINATOR
if ( persistentClass.isPolymorphic() ) {
forceDiscriminator = persistentClass.isForceDiscriminator();
final Value discriminatorMapping = persistentClass.getDiscriminator();
if ( discriminatorMapping != null ) {
log.debug( "Encountered explicit discriminator mapping for joined inheritance" );
final Selectable selectable = discriminatorMapping.getSelectables().get(0);
if ( selectable instanceof Formula ) {
throw new MappingException( "Discriminator formulas on joined inheritance hierarchies not supported at this time" );
@ -230,6 +235,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
.resolve( StandardBasicTypes.INTEGER );
discriminatorValue = null;
discriminatorSQLString = null;
forceDiscriminator = false;
}
if ( optimisticLockStyle().isAllOrDirty() ) {
@ -311,10 +317,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
}
hasDuplicateTables = new HashSet<>( tableNames ).size() == tableNames.size();
naturalOrderTableNames = ArrayHelper.toStringArray( tableNames );
naturalOrderTableKeyColumns = ArrayHelper.to2DStringArray( keyColumns );
String[][] naturalOrderTableKeyColumnReaders = ArrayHelper.to2DStringArray(keyColumnReaders);
String[][] naturalOrderTableKeyColumnReaderTemplates = ArrayHelper.to2DStringArray(keyColumnReaderTemplates);
naturalOrderTableNames = toStringArray( tableNames );
naturalOrderTableKeyColumns = to2DStringArray( keyColumns );
String[][] naturalOrderTableKeyColumnReaders = to2DStringArray(keyColumnReaders);
String[][] naturalOrderTableKeyColumnReaderTemplates = to2DStringArray(keyColumnReaderTemplates);
naturalOrderCascadeDeleteEnabled = ArrayHelper.toBooleanArray( cascadeDeletes );
ArrayList<String> subclassTableNames = new ArrayList<>();
@ -361,8 +367,8 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
keyColumns.add( key );
}
String[] naturalOrderSubclassTableNameClosure = ArrayHelper.toStringArray( subclassTableNames );
String[][] naturalOrderSubclassTableKeyColumnClosure = ArrayHelper.to2DStringArray( keyColumns );
String[] naturalOrderSubclassTableNameClosure = toStringArray( subclassTableNames );
String[][] naturalOrderSubclassTableKeyColumnClosure = to2DStringArray( keyColumns );
isClassOrSuperclassTable = ArrayHelper.toBooleanArray( isConcretes );
// subclassTableSequentialSelect = ArrayHelper.toBooleanArray( isDeferreds );
// subclassTableIsLazyClosure = ArrayHelper.toBooleanArray( isLazies );
@ -396,7 +402,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
spaces = ArrayHelper.join(
this.tableNames,
ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
toStringArray( persistentClass.getSynchronizedTables() )
);
// Custom sql
@ -419,7 +425,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
customSQLInsert[jk] = pc.getCustomSQLInsert();
insertCallable[jk] = customSQLInsert[jk] != null && pc.isCustomInsertCallable();
insertExpectations[jk] = Expectations.appropriateExpectation(
insertExpectations[jk] = appropriateExpectation(
pc.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[jk], insertCallable[jk] )
: pc.getCustomSQLInsertCheckStyle()
@ -427,7 +433,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
customSQLUpdate[jk] = pc.getCustomSQLUpdate();
updateCallable[jk] = customSQLUpdate[jk] != null && pc.isCustomUpdateCallable();
updateExpectations[jk] = Expectations.appropriateExpectation(
updateExpectations[jk] = appropriateExpectation(
pc.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[jk], updateCallable[jk] )
: pc.getCustomSQLUpdateCheckStyle()
@ -435,7 +441,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
customSQLDelete[jk] = pc.getCustomSQLDelete();
deleteCallable[jk] = customSQLDelete[jk] != null && pc.isCustomDeleteCallable();
deleteExpectations[jk] = Expectations.appropriateExpectation(
deleteExpectations[jk] = appropriateExpectation(
pc.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[jk], deleteCallable[jk] )
: pc.getCustomSQLDeleteCheckStyle()
@ -456,7 +462,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
customSQLInsert[j] = join.getCustomSQLInsert();
insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
insertExpectations[j] = Expectations.appropriateExpectation(
insertExpectations[j] = appropriateExpectation(
join.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
: join.getCustomSQLInsertCheckStyle()
@ -464,7 +470,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
customSQLUpdate[j] = join.getCustomSQLUpdate();
updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
updateExpectations[j] = Expectations.appropriateExpectation(
updateExpectations[j] = appropriateExpectation(
join.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
: join.getCustomSQLUpdateCheckStyle()
@ -472,7 +478,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
customSQLDelete[j] = join.getCustomSQLDelete();
deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
deleteExpectations[j] = Expectations.appropriateExpectation(
deleteExpectations[j] = appropriateExpectation(
join.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
: join.getCustomSQLDeleteCheckStyle()
@ -525,7 +531,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
subclassColumnTableNumberClosure = ArrayHelper.toIntArray( columnTableNumbers );
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray( propTableNumbers );
// subclassFormulaTableNumberClosure = ArrayHelper.toIntArray( formulaTableNumbers );
subclassColumnClosure = ArrayHelper.toStringArray( columns );
subclassColumnClosure = toStringArray( columns );
// SUBCLASSES
@ -669,18 +675,14 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
final Set<String> classNames = new HashSet<>();
for ( Subclass subclass : persistentClass.getDirectSubclasses() ) {
final Set<String> subclassSubclassNames = processPersistentClassHierarchy(
subclass,
false,
factory,
mapping
);
final Set<String> subclassSubclassNames =
processPersistentClassHierarchy( subclass, false, factory, mapping );
classNames.addAll( subclassSubclassNames );
}
classNames.add( persistentClass.getEntityName() );
if ( ! isBase ) {
if ( !isBase ) {
MappedSuperclass msc = persistentClass.getSuperMappedSuperclass();
while ( msc != null ) {
classNames.add( msc.getMappedClass().getName() );
@ -699,16 +701,13 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
String[][] mapping,
SessionFactoryImplementor factory) {
final String tableName = persistentClass.getTable().getQualifiedName(
factory.getSqlStringGenerationContext()
);
final String tableName = persistentClass.getTable()
.getQualifiedName( factory.getSqlStringGenerationContext() );
associateSubclassNamesToSubclassTableIndex( tableName, classNames, mapping );
for ( Join join : persistentClass.getJoins() ) {
final String secondaryTableName = join.getTable().getQualifiedName(
factory.getSqlStringGenerationContext()
);
final String secondaryTableName = join.getTable()
.getQualifiedName( factory.getSqlStringGenerationContext() );
associateSubclassNamesToSubclassTableIndex( secondaryTableName, classNames, mapping );
}
}
@ -719,7 +718,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
String[][] mapping) {
// find the table's entry in the subclassTableNameClosure array
boolean found = false;
for ( int i = 0; i < subclassTableNameClosure.length; i++ ) {
for ( int i = 1; i < subclassTableNameClosure.length; i++ ) {
if ( subclassTableNameClosure[i].equals( tableName ) ) {
found = true;
final int index = i - coreTableSpan;
@ -733,7 +732,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
)
);
}
mapping[index] = ArrayHelper.toStringArray( classNames );
mapping[index] = toStringArray( classNames );
break;
}
}
@ -747,6 +746,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
}
}
protected boolean needsDiscriminator() {
return forceDiscriminator;
}
@Override
public boolean isNullableTable(int j) {
return isNullableTable[j];
@ -757,7 +760,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
for ( int i = 0; i < naturalOrderTableNames.length; i++ ) {
final String tableName = naturalOrderTableNames[i];
final int tableIndex = i;
consumer.consume(
tableName,
tableIndex,
@ -852,29 +854,29 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
@Override
public String getSubclassForDiscriminatorValue(Object value) {
if ( value == null ) {
return subclassesByDiscriminatorValue.get( DiscriminatorHelper.NULL_DISCRIMINATOR );
return subclassesByDiscriminatorValue.get( NULL_DISCRIMINATOR );
}
else {
String result = subclassesByDiscriminatorValue.get( value );
if ( result == null ) {
result = subclassesByDiscriminatorValue.get( DiscriminatorHelper.NOT_NULL_DISCRIMINATOR );
}
return result;
final String result = subclassesByDiscriminatorValue.get( value );
return result == null ? subclassesByDiscriminatorValue.get( NOT_NULL_DISCRIMINATOR ) : result;
}
}
@Override
protected Map<Object, EntityDiscriminatorMapping.DiscriminatorValueDetails> buildDiscriminatorValueMappings(PersistentClass bootEntityDescriptor, MappingModelCreationProcess modelCreationProcess) {
protected Map<Object, DiscriminatorValueDetails> buildDiscriminatorValueMappings(
PersistentClass bootEntityDescriptor,
MappingModelCreationProcess modelCreationProcess) {
final MappingMetamodelImplementor mappingModel = modelCreationProcess.getCreationContext()
.getSessionFactory()
.getMappingMetamodel();
//noinspection unchecked
final JdbcLiteralFormatter<Object> jdbcLiteralFormatter = (JdbcLiteralFormatter<Object>) discriminatorType.getJdbcLiteralFormatter();
final Dialect dialect = modelCreationProcess.getCreationContext().getSessionFactory().getJdbcServices().getDialect();
final Map<Object, EntityDiscriminatorMapping.DiscriminatorValueDetails> valueMappings = new ConcurrentHashMap<>();
final JdbcLiteralFormatter<Object> jdbcLiteralFormatter =
(JdbcLiteralFormatter<Object>) discriminatorType.getJdbcLiteralFormatter();
final Dialect dialect = modelCreationProcess.getCreationContext()
.getSessionFactory().getJdbcServices().getDialect();
final Map<Object, DiscriminatorValueDetails> valueMappings = new ConcurrentHashMap<>();
subclassesByDiscriminatorValue.forEach( (value, entityName) -> {
final String jdbcLiteral = value == NULL_DISCRIMINATOR || value == NOT_NULL_DISCRIMINATOR
? null
@ -1008,7 +1010,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
@Override
public String getRootTableName() {
return naturalOrderTableNames[0];
return naturalOrderTableNames[0];
}
@Override
@ -1200,7 +1202,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
final boolean encapsulated = ! cidType.isEmbedded();
if ( encapsulated ) {
// we have an `@EmbeddedId`
return MappingModelCreationHelper.buildEncapsulatedCompositeIdentifierMapping(
return buildEncapsulatedCompositeIdentifierMapping(
this,
bootEntityDescriptor.getIdentifierProperty(),
bootEntityDescriptor.getIdentifierProperty().getName(),
@ -1259,7 +1261,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
protected EntityDiscriminatorMapping generateDiscriminatorMapping(
PersistentClass bootEntityDescriptor,
MappingModelCreationProcess modelCreationProcess) {
EntityMappingType superMappingType = getSuperMappingType();
final EntityMappingType superMappingType = getSuperMappingType();
if ( superMappingType != null ) {
return superMappingType.getDiscriminatorMapping();
}
@ -1273,8 +1275,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
return super.generateDiscriminatorMapping( bootEntityDescriptor, modelCreationProcess );
}
org.hibernate.persister.entity.DiscriminatorType<?> discriminatorMetadataType = (org.hibernate.persister.entity.DiscriminatorType<?>) getTypeDiscriminatorMetadata().getResolutionType();
// otherwise, we need to use the case-statement approach
return new CaseStatementDiscriminatorMappingImpl(
this,
@ -1283,7 +1283,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
notNullColumnNames,
discriminatorValues,
subclassNameByTableName,
discriminatorMetadataType,
(DiscriminatorType<?>) getTypeDiscriminatorMetadata().getResolutionType(),
buildDiscriminatorValueMappings( bootEntityDescriptor, modelCreationProcess ),
modelCreationProcess
);
@ -1394,11 +1394,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
if ( oldJoin.getJoinType() != SqlAstJoinType.INNER
&& sharedSuperclassTables.contains( joinedTableReference.getTableExpression() ) ) {
tableReferenceJoins.add(
new TableReferenceJoin(
true,
joinedTableReference,
oldJoin.getPredicate()
)
new TableReferenceJoin( true, joinedTableReference, oldJoin.getPredicate() )
);
}
else {
@ -1418,7 +1414,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
for ( int i = 0; i < constraintOrderedTableNames.length; i++ ) {
final String tableName = constraintOrderedTableNames[i];
final int tablePosition = i;
consumer.consume(
tableName,
() -> columnConsumer -> columnConsumer.accept( tableName, constraintOrderedKeyColumnNames[tablePosition] )

View File

@ -13,8 +13,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
@ -26,11 +24,8 @@ import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.DynamicFilterAliasGenerator;
import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jdbc.Expectation;
import org.hibernate.jdbc.Expectations;
import org.hibernate.mapping.Column;
import org.hibernate.mapping.Formula;
import org.hibernate.mapping.Join;
@ -47,32 +42,22 @@ import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.spi.PersisterCreationContext;
import org.hibernate.query.sqm.ComparisonOperator;
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.InFragment;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAliasBase;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
import org.hibernate.sql.ast.tree.from.NamedTableReference;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.InListPredicate;
import org.hibernate.sql.ast.tree.predicate.Junction;
import org.hibernate.sql.ast.tree.predicate.NegatedPredicate;
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.model.ast.builder.MutationGroupBuilder;
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
import org.hibernate.type.BasicType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import static org.hibernate.internal.util.collections.ArrayHelper.to2DStringArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toBooleanArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toIntArray;
import static org.hibernate.internal.util.collections.ArrayHelper.toStringArray;
import static org.hibernate.internal.util.collections.CollectionHelper.toSmallMap;
import static org.hibernate.jdbc.Expectations.appropriateExpectation;
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
import static org.hibernate.sql.model.ast.builder.TableMutationBuilder.NULL;
@ -144,9 +129,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
//private final Map propertyTableNumbersByName = new HashMap();
// private final Map<String, Integer> propertyTableNumbersByNameAndSubclass;
private final String[] fullDiscriminatorSQLValues;
private final Object[] fullDiscriminatorValues;
//INITIALIZATION:
@Deprecated(since = "6.0")
@ -202,7 +184,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
customSQLInsert[0] = persistentClass.getCustomSQLInsert();
insertCallable[0] = customSQLInsert[0] != null && persistentClass.isCustomInsertCallable();
insertExpectations[0] = Expectations.appropriateExpectation(
insertExpectations[0] = appropriateExpectation(
persistentClass.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[0], insertCallable[0] )
: persistentClass.getCustomSQLInsertCheckStyle()
@ -210,7 +192,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
customSQLUpdate[0] = persistentClass.getCustomSQLUpdate();
updateCallable[0] = customSQLUpdate[0] != null && persistentClass.isCustomUpdateCallable();
updateExpectations[0] = Expectations.appropriateExpectation(
updateExpectations[0] = appropriateExpectation(
persistentClass.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[0], updateCallable[0] )
: persistentClass.getCustomSQLUpdateCheckStyle()
@ -218,7 +200,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
customSQLDelete[0] = persistentClass.getCustomSQLDelete();
deleteCallable[0] = customSQLDelete[0] != null && persistentClass.isCustomDeleteCallable();
deleteExpectations[0] = Expectations.appropriateExpectation(
deleteExpectations[0] = appropriateExpectation(
persistentClass.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[0], deleteCallable[0] )
: persistentClass.getCustomSQLDeleteCheckStyle()
@ -239,7 +221,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
customSQLInsert[j] = join.getCustomSQLInsert();
insertCallable[j] = customSQLInsert[j] != null && join.isCustomInsertCallable();
insertExpectations[j] = Expectations.appropriateExpectation(
insertExpectations[j] = appropriateExpectation(
join.getCustomSQLInsertCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLInsert[j], insertCallable[j] )
: join.getCustomSQLInsertCheckStyle()
@ -247,7 +229,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
customSQLUpdate[j] = join.getCustomSQLUpdate();
updateCallable[j] = customSQLUpdate[j] != null && join.isCustomUpdateCallable();
updateExpectations[j] = Expectations.appropriateExpectation(
updateExpectations[j] = appropriateExpectation(
join.getCustomSQLUpdateCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLUpdate[j], updateCallable[j] )
: join.getCustomSQLUpdateCheckStyle()
@ -255,7 +237,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
customSQLDelete[j] = join.getCustomSQLDelete();
deleteCallable[j] = customSQLDelete[j] != null && join.isCustomDeleteCallable();
deleteExpectations[j] = Expectations.appropriateExpectation(
deleteExpectations[j] = appropriateExpectation(
join.getCustomSQLDeleteCheckStyle() == null
? ExecuteUpdateResultCheckStyle.determineDefault( customSQLDelete[j], deleteCallable[j] )
: join.getCustomSQLDeleteCheckStyle()
@ -279,7 +261,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
spaces = ArrayHelper.join(
qualifiedTableNames,
ArrayHelper.toStringArray( persistentClass.getSynchronizedTables() )
toStringArray( persistentClass.getSynchronizedTables() )
);
// final boolean lazyAvailable = isInstrumented();
@ -294,12 +276,12 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
// ArrayList<Boolean> isLazies = new ArrayList<>();
subclassTables.add( qualifiedTableNames[0] );
joinKeyColumns.add( getIdentifierColumnNames() );
isConcretes.add( Boolean.TRUE );
isClassOrSuperclassJoins.add( Boolean.TRUE );
// isDeferreds.add( Boolean.FALSE );
isInverses.add( Boolean.FALSE );
isNullables.add( Boolean.FALSE );
// isLazies.add( Boolean.FALSE );
isConcretes.add( true );
isClassOrSuperclassJoins.add( true );
// isDeferreds.add( false );
isInverses.add( false );
isNullables.add( false );
// isLazies.add( false );
for ( Join join : persistentClass.getSubclassJoinClosure() ) {
isConcretes.add( persistentClass.isClassOrSuperclassTable( join.getTable() ) );
isClassOrSuperclassJoins.add( persistentClass.isClassOrSuperclassJoin( join ) );
@ -310,26 +292,25 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
// boolean isDeferred = join.isSequentialSelect() && !persistentClass.isClassOrSuperclassJoin( join );
// isDeferreds.add( isDeferred );
String joinTableName = determineTableName( join.getTable() );
final String joinTableName = determineTableName( join.getTable() );
subclassTables.add( joinTableName );
String[] keyCols = new String[join.getKey().getColumnSpan()];
final String[] keyCols = new String[join.getKey().getColumnSpan()];
List<Column> columns = join.getKey().getColumns();
for ( int i = 0; i < columns.size(); i++ ) {
Column col = columns.get( i );
keyCols[i] = col.getQuotedName( dialect );
keyCols[i] = columns.get( i ).getQuotedName( dialect );
}
joinKeyColumns.add( keyCols );
}
// subclassTableSequentialSelect = ArrayHelper.toBooleanArray( isDeferreds );
subclassTableNameClosure = ArrayHelper.toStringArray( subclassTables );
subclassTableNameClosure = toStringArray( subclassTables );
// subclassTableIsLazyClosure = ArrayHelper.toBooleanArray( isLazies );
subclassTableKeyColumnClosure = ArrayHelper.to2DStringArray( joinKeyColumns );
isClassOrSuperclassTable = ArrayHelper.toBooleanArray( isConcretes );
isClassOrSuperclassJoin = ArrayHelper.toBooleanArray( isClassOrSuperclassJoins );
isInverseSubclassTable = ArrayHelper.toBooleanArray( isInverses );
isNullableSubclassTable = ArrayHelper.toBooleanArray( isNullables );
subclassTableKeyColumnClosure = to2DStringArray( joinKeyColumns );
isClassOrSuperclassTable = toBooleanArray( isConcretes );
isClassOrSuperclassJoin = toBooleanArray( isClassOrSuperclassJoins );
isInverseSubclassTable = toBooleanArray( isInverses );
isNullableSubclassTable = toBooleanArray( isNullables );
// DISCRIMINATOR
@ -339,7 +320,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
throw new MappingException( "discriminator mapping required for single table polymorphic persistence" );
}
forceDiscriminator = persistentClass.isForceDiscriminator();
Selectable selectable = discriminator.getSelectables().get( 0 );
final Selectable selectable = discriminator.getSelectables().get( 0 );
SqmFunctionRegistry functionRegistry = factory.getQueryEngine().getSqmFunctionRegistry();
discriminatorType = DiscriminatorHelper.getDiscriminatorType( persistentClass );
discriminatorValue = DiscriminatorHelper.getDiscriminatorValue( persistentClass );
@ -359,7 +340,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
discriminatorAlias = "clazz_";
}
else {
Column column = (Column) selectable;
final Column column = (Column) selectable;
discriminatorColumnName = column.getQuotedName( dialect );
discriminatorColumnReaders = column.getReadExpr( dialect );
discriminatorColumnReaderTemplate = column.getTemplate(
@ -389,7 +370,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
// PROPERTIES
propertyTableNumbers = new int[getPropertySpan()];
List<Property> propertyClosure = persistentClass.getPropertyClosure();
final List<Property> propertyClosure = persistentClass.getPropertyClosure();
for ( int k = 0; k < propertyClosure.size(); k++ ) {
propertyTableNumbers[k] = persistentClass.getJoinNumber( propertyClosure.get( k ) );
}
@ -408,10 +389,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
propertyJoinNumbers.add( join );
}
subclassPropertyTableNumberClosure = ArrayHelper.toIntArray( propertyJoinNumbers );
subclassPropertyTableNumberClosure = toIntArray( propertyJoinNumbers );
final List<Object> values = new ArrayList<>();
final List<String> sqlValues = new ArrayList<>();
int subclassSpan = persistentClass.getSubclassSpan() + 1;
subclassClosure = new String[subclassSpan];
subclassClosure[0] = getEntityName();
@ -422,13 +401,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
getEntityName()
);
if ( !getEntityMetamodel().isAbstract() ) {
values.add( discriminatorValue );
sqlValues.add( discriminatorSQLValue );
}
// SUBCLASSES
List<Subclass> subclasses = persistentClass.getSubclasses();
final List<Subclass> subclasses = persistentClass.getSubclasses();
for ( int k = 0; k < subclasses.size(); k++ ) {
Subclass subclass = subclasses.get( k );
subclassClosure[k] = subclass.getEntityName();
@ -438,23 +412,11 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
subclassDiscriminatorValue,
subclass.getEntityName()
);
//copy/paste from EntityMetamodel:
boolean subclassAbstract = subclass.isAbstract() == null
? subclass.hasPojoRepresentation() && ReflectHelper.isAbstractClass( subclass.getMappedClass() )
: subclass.isAbstract();
if ( !subclassAbstract ) {
values.add( subclassDiscriminatorValue );
sqlValues.add( DiscriminatorHelper.getDiscriminatorSQLValue( subclass, dialect, factory ) );
}
}
}
// Don't hold a reference to an empty HashMap:
subclassesByDiscriminatorValue = CollectionHelper.toSmallMap( subclassesByDiscriminatorValueLocal );
fullDiscriminatorSQLValues = ArrayHelper.toStringArray( sqlValues );
fullDiscriminatorValues = ArrayHelper.toObjectArray( values );
subclassesByDiscriminatorValue = toSmallMap( subclassesByDiscriminatorValueLocal );
initSubclassPropertyAliasesMap( persistentClass );
@ -463,16 +425,16 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
private static boolean isDiscriminatorInsertable(PersistentClass persistentClass) {
return !persistentClass.isDiscriminatorValueNull()
&& !persistentClass.isDiscriminatorValueNotNull()
&& persistentClass.isDiscriminatorInsertable()
&& !persistentClass.getDiscriminator().hasFormula();
&& !persistentClass.isDiscriminatorValueNotNull()
&& persistentClass.isDiscriminatorInsertable()
&& !persistentClass.getDiscriminator().hasFormula();
}
private static void addSubclassByDiscriminatorValue(
Map<Object, String> subclassesByDiscriminatorValue,
Object discriminatorValue,
String entityName) {
String mappedEntityName = subclassesByDiscriminatorValue.put( discriminatorValue, entityName );
final String mappedEntityName = subclassesByDiscriminatorValue.put( discriminatorValue, entityName );
if ( mappedEntityName != null ) {
throw new MappingException(
"Entities [" + entityName + "] and [" + mappedEntityName
@ -561,11 +523,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
return subclassesByDiscriminatorValue.get( NULL_DISCRIMINATOR );
}
else {
String result = subclassesByDiscriminatorValue.get( value );
if ( result == null ) {
result = subclassesByDiscriminatorValue.get( DiscriminatorHelper.NOT_NULL_DISCRIMINATOR );
}
return result;
final String result = subclassesByDiscriminatorValue.get( value );
return result == null ? subclassesByDiscriminatorValue.get( NOT_NULL_DISCRIMINATOR ) : result;
}
}
@ -574,7 +533,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
return spaces;
}
private boolean isDiscriminatorFormula() {
@Override
protected boolean isDiscriminatorFormula() {
return discriminatorColumnName == null;
}
@ -615,7 +575,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
return getTableName() + ' ' + name;
}
private boolean needsDiscriminator() {
@Override
protected boolean needsDiscriminator() {
return forceDiscriminator || isInherited();
}
@ -716,11 +677,12 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
.getMappingMetamodel();
//noinspection unchecked
final JdbcLiteralFormatter<Object> jdbcLiteralFormatter = (JdbcLiteralFormatter<Object>) discriminatorType.getJdbcLiteralFormatter();
final Dialect dialect = modelCreationProcess.getCreationContext().getSessionFactory().getJdbcServices().getDialect();
final JdbcLiteralFormatter<Object> jdbcLiteralFormatter =
(JdbcLiteralFormatter<Object>) discriminatorType.getJdbcLiteralFormatter();
final Dialect dialect = modelCreationProcess.getCreationContext()
.getSessionFactory().getJdbcServices().getDialect();
final Map<Object, DiscriminatorValueDetails> valueMappings = new ConcurrentHashMap<>();
subclassesByDiscriminatorValue.forEach( (value, entityName) -> {
final String jdbcLiteral = value == NULL_DISCRIMINATOR || value == NOT_NULL_DISCRIMINATOR
? null
@ -751,142 +713,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
return new DynamicFilterAliasGenerator( qualifiedTableNames, rootAlias );
}
@Override
public TableGroup createRootTableGroup(
boolean canUseInnerJoins,
NavigablePath navigablePath,
String explicitSourceAlias,
Supplier<Consumer<Predicate>> additionalPredicateCollectorAccess,
SqlAliasBase sqlAliasBase,
SqlExpressionResolver expressionResolver,
FromClauseAccess fromClauseAccess,
SqlAstCreationContext creationContext) {
final TableGroup tableGroup = super.createRootTableGroup(
canUseInnerJoins,
navigablePath,
explicitSourceAlias,
additionalPredicateCollectorAccess,
sqlAliasBase,
expressionResolver,
fromClauseAccess,
creationContext
);
if ( additionalPredicateCollectorAccess != null && needsDiscriminator() ) {
final Predicate discriminatorPredicate = createDiscriminatorPredicate(
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
tableGroup,
expressionResolver
);
additionalPredicateCollectorAccess.get().accept( discriminatorPredicate );
}
return tableGroup;
}
@Override
public void applyDiscriminator(
Consumer<Predicate> predicateConsumer,
String alias,
TableGroup tableGroup,
SqlAstCreationState creationState) {
if ( needsDiscriminator() ) {
predicateConsumer.accept(
createDiscriminatorPredicate(
alias,
tableGroup,
creationState.getSqlExpressionResolver()
)
);
}
super.applyDiscriminator( predicateConsumer, alias, tableGroup, creationState );
}
private Predicate createDiscriminatorPredicate(
String alias,
TableGroup tableGroup,
SqlExpressionResolver sqlExpressionResolver) {
final SqlExpressionResolver.ColumnReferenceKey columnReferenceKey;
final String discriminatorExpression;
if ( isDiscriminatorFormula() ) {
discriminatorExpression = getDiscriminatorFormulaTemplate();
columnReferenceKey = SqlExpressionResolver.createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
getDiscriminatorFormulaTemplate()
);
}
else {
discriminatorExpression = getDiscriminatorColumnName();
columnReferenceKey = SqlExpressionResolver.createColumnReferenceKey(
tableGroup.getPrimaryTableReference(),
getDiscriminatorColumnName()
);
}
final BasicType<?> discriminatorType = (BasicType<?>) getDiscriminatorMapping().getJdbcMapping();
final Expression sqlExpression = sqlExpressionResolver.resolveSqlExpression(
columnReferenceKey,
sqlAstProcessingState -> new ColumnReference(
alias,
discriminatorExpression,
isDiscriminatorFormula(),
null,
null,
discriminatorType.getJdbcMapping()
)
);
if ( hasSubclasses() ) {
final List<Expression> values = new ArrayList<>( fullDiscriminatorValues.length );
boolean hasNull = false, hasNonNull = false;
for ( Object discriminatorValue : fullDiscriminatorValues ) {
if ( discriminatorValue == NULL_DISCRIMINATOR ) {
hasNull = true;
}
else if ( discriminatorValue == DiscriminatorHelper.NOT_NULL_DISCRIMINATOR ) {
hasNonNull = true;
}
else {
values.add( new QueryLiteral<>( discriminatorValue, discriminatorType ) );
}
}
final Predicate p = new InListPredicate( sqlExpression, values );
if ( hasNull || hasNonNull ) {
final Junction junction = new Junction(
Junction.Nature.DISJUNCTION
);
// This essentially means we need to select everything, so we don't need a predicate at all
// so we return an empty Junction
if ( hasNull && hasNonNull ) {
return junction;
}
junction.add( new NullnessPredicate( sqlExpression ) );
junction.add( p );
return junction;
}
return p;
}
final Object value = getDiscriminatorValue();
final boolean hasNotNullDiscriminator = value == DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
final boolean hasNullDiscriminator = value == NULL_DISCRIMINATOR;
if ( hasNotNullDiscriminator || hasNullDiscriminator ) {
final NullnessPredicate nullnessPredicate = new NullnessPredicate( sqlExpression );
if ( hasNotNullDiscriminator ) {
return new NegatedPredicate( nullnessPredicate );
}
return nullnessPredicate;
}
return new ComparisonPredicate(
sqlExpression,
ComparisonOperator.EQUAL,
new QueryLiteral<>( value, discriminatorType )
);
}
@Override
public void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
if ( !needsDiscriminator() && treatedEntityNames.isEmpty() ) {
@ -913,8 +739,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
}
if ( treatTargetType.hasSubclasses() ) {
// if the treat is an abstract class, add the concrete implementations to values if any
Set<String> actualSubClasses = treatTargetType.getSubclassEntityNames();
final Set<String> actualSubClasses = treatTargetType.getSubclassEntityNames();
for ( String actualSubClass : actualSubClasses ) {
if ( actualSubClass.equals( subclass ) ) {
continue;
@ -938,7 +763,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
for ( int i = 0; i < constraintOrderedTableNames.length; i++ ) {
final String tableName = constraintOrderedTableNames[i];
final int tablePosition = i;
consumer.consume(
tableName,
() -> columnConsumer -> columnConsumer.accept(
@ -954,11 +778,10 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
for ( int i = 0; i < qualifiedTableNames.length; i++ ) {
final String tableName = qualifiedTableNames[i];
final int tableIndex = i;
consumer.consume(
tableName,
tableIndex,
() -> (columnConsumer) -> columnConsumer.accept(
() -> columnConsumer -> columnConsumer.accept(
tableName,
getIdentifierMapping(),
keyColumnNames[tableIndex]

View File

@ -258,6 +258,14 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
return false;
}
@Override
public UnionTableReference createPrimaryTableReference(
SqlAliasBase sqlAliasBase,
SqlExpressionResolver expressionResolver,
SqlAstCreationContext creationContext) {
return new UnionTableReference( getTableName(), subclassTableExpressions, sqlAliasBase.generateNewAlias() );
}
@Override
public TableGroup createRootTableGroup(
boolean canUseInnerJoins,
@ -268,19 +276,18 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
SqlExpressionResolver expressionResolver,
FromClauseAccess fromClauseAccess,
SqlAstCreationContext creationContext) {
final UnionTableReference tableReference = resolvePrimaryTableReference( sqlAliasBase );
return new UnionTableGroup( canUseInnerJoins, navigablePath, tableReference, this, explicitSourceAlias );
return new UnionTableGroup(
canUseInnerJoins,
navigablePath,
createPrimaryTableReference( sqlAliasBase, expressionResolver, creationContext ),
this,
explicitSourceAlias
);
}
@Override
protected UnionTableReference resolvePrimaryTableReference(SqlAliasBase sqlAliasBase) {
return new UnionTableReference(
getTableName(),
subclassTableExpressions,
sqlAliasBase.generateNewAlias(),
false
);
protected boolean needsDiscriminator() {
return false;
}
@Override

View File

@ -167,7 +167,6 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
.buildSelectTranslator( factory, statement );
final Expression count = createCountStar( factory, sqmConverter );
//noinspection rawtypes,unchecked
domainResults.add(
new BasicResult<>(
0,
@ -180,8 +179,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
new CteTableGroup(
new NamedTableReference(
idSelectCte.getCteTable().getTableExpression(),
CTE_TABLE_IDENTIFIER,
false
CTE_TABLE_IDENTIFIER
)
)
);
@ -270,8 +268,7 @@ public abstract class AbstractCteMutationHandler extends AbstractMutationHandler
SessionFactoryImplementor factory) {
final NamedTableReference idSelectTableReference = new NamedTableReference(
idSelectCte.getCteTable().getTableExpression(),
CTE_TABLE_IDENTIFIER,
false
CTE_TABLE_IDENTIFIER
);
final List<CteColumn> cteColumns = idSelectCte.getCteTable().getCteColumns();
final int size = cteColumns.size();

View File

@ -412,13 +412,7 @@ public class CteInsertHandler implements InsertHandler {
{
final QuerySpec rowsWithSequenceQuery = new QuerySpec( true );
rowsWithSequenceQuery.getFromClause().addRoot(
new CteTableGroup(
new NamedTableReference(
baseTableName,
"e",
false
)
)
new CteTableGroup( new NamedTableReference( baseTableName, "e" ) )
);
rowsWithSequenceQuery.getSelectClause().addSqlSelection(
new SqlSelectionImpl(
@ -469,18 +463,13 @@ public class CteInsertHandler implements InsertHandler {
final TableGroup baseTableGroup = new TableGroupImpl(
navigablePath,
null,
new NamedTableReference(
baseTableName,
"e",
false
),
new NamedTableReference( baseTableName, "e" ),
null
);
final TableGroup rowsWithSequenceTableGroup = new CteTableGroup(
new NamedTableReference(
ROW_NUMBERS_WITH_SEQUENCE_VALUE,
"t",
false
"t"
)
);
baseTableGroup.addTableGroupJoin(
@ -639,8 +628,7 @@ public class CteInsertHandler implements InsertHandler {
new NamedTableReference(
// We want to return the insertion count of the base table
baseInsertCte,
CTE_TABLE_IDENTIFIER,
false
CTE_TABLE_IDENTIFIER
)
)
);
@ -815,11 +803,7 @@ public class CteInsertHandler implements InsertHandler {
final String baseTableName = "base_" + queryCte.getCteTable().getTableExpression();
insertSelectSpec.getFromClause().addRoot(
new CteTableGroup(
new NamedTableReference(
baseTableName,
"e",
false
)
new NamedTableReference( baseTableName, "e" )
)
);
final CteColumn rowNumberColumn = queryCte.getCteTable().getCteColumns().get(
@ -864,18 +848,13 @@ public class CteInsertHandler implements InsertHandler {
final TableGroup baseTableGroup = new TableGroupImpl(
navigablePath,
null,
new NamedTableReference(
baseTableName,
"e",
false
),
new NamedTableReference( baseTableName, "e" ),
null
);
final TableGroup rootInsertCteTableGroup = new CteTableGroup(
new NamedTableReference(
getCteTableName( tableExpression ),
"t",
false
"t"
)
);
baseTableGroup.addTableGroupJoin(
@ -947,8 +926,7 @@ public class CteInsertHandler implements InsertHandler {
new CteTableGroup(
new NamedTableReference(
dmlResultCte.getTableExpression(),
"e",
false
"e"
)
)
);
@ -997,8 +975,7 @@ public class CteInsertHandler implements InsertHandler {
new CteTableGroup(
new NamedTableReference(
queryCte.getCteTable().getTableExpression(),
"e",
false
"e"
)
)
);

View File

@ -181,8 +181,7 @@ public class CteUpdateHandler extends AbstractCteMutationHandler implements Upda
);
final NamedTableReference existsTableReference = new NamedTableReference(
tableExpression,
"dml_",
false
"dml_"
);
final List<ColumnReference> existsKeyColumns = new ArrayList<>( idSelectCte.getCteTable().getCteColumns().size() );
final String[] keyColumns = entityPersister.getKeyColumns( i );

View File

@ -157,8 +157,7 @@ public class InlineDeleteHandler implements DeleteHandler {
DomainQueryExecutionContext executionContext) {
final NamedTableReference targetTableReference = new NamedTableReference(
targetTableExpression,
DeleteStatement.DEFAULT_ALIAS,
false
DeleteStatement.DEFAULT_ALIAS
);
final SqmJdbcExecutionContextAdapter executionContextAdapter = SqmJdbcExecutionContextAdapter.omittingLockingAndPaging( executionContext );

View File

@ -67,8 +67,7 @@ public final class ExecuteWithTemporaryTableHelper {
final NamedTableReference idTableReference = new NamedTableReference(
idTable.getTableExpression(),
InsertSelectStatement.DEFAULT_ALIAS,
false
InsertSelectStatement.DEFAULT_ALIAS
);
final InsertSelectStatement idTableInsert = new InsertSelectStatement( idTableReference );

View File

@ -323,8 +323,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
final QuerySpec querySpec = new QuerySpec( true );
final NamedTableReference temporaryTableReference = new NamedTableReference(
insertStatement.getTargetTable().getTableExpression(),
updatingTableReference.getIdentificationVariable(),
false
updatingTableReference.getIdentificationVariable()
);
final TableGroupImpl temporaryTableGroup = new TableGroupImpl(
updatingTableGroup.getNavigablePath(),
@ -687,8 +686,7 @@ public class InsertExecutionDelegate implements TableBasedInsertHandler.Executio
null,
new NamedTableReference(
insertStatement.getTargetTable().getTableExpression(),
updatingTableReference.getIdentificationVariable(),
false
updatingTableReference.getIdentificationVariable()
),
entityDescriptor
);

View File

@ -297,8 +297,7 @@ public class RestrictedDeleteExecutionDelegate implements TableBasedDeleteHandle
(tableExpression, tableKeyColumnVisitationSupplier) -> {
final NamedTableReference tableReference = new NamedTableReference(
tableExpression,
tableGroup.getPrimaryTableReference().getIdentificationVariable(),
false
tableGroup.getPrimaryTableReference().getIdentificationVariable()
);
final QuerySpec idMatchingSubQuerySpec;
// No need for a predicate if there is no supplied predicate i.e. this is a full cleanup

View File

@ -338,8 +338,7 @@ public class UpdateExecutionDelegate implements TableBasedUpdateHandler.Executio
);
final NamedTableReference existsTableReference = new NamedTableReference(
tableExpression,
"dml_",
false
"dml_"
);
existsQuerySpec.getFromClause().addRoot(
new TableGroupImpl(

View File

@ -2836,7 +2836,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
navigablePath,
sqlAliasBase,
tableGroupProducer,
new NamedTableReference( cteName, identifierVariable, false ),
new NamedTableReference( cteName, identifierVariable ),
tableGroupProducer.getCompatibleTableExpressions()
);
}

View File

@ -27,6 +27,12 @@ public class NamedTableReference extends AbstractTableReference {
private String prunedTableExpression;
public NamedTableReference(
String tableExpression,
String identificationVariable) {
this( tableExpression, identificationVariable, false );
}
public NamedTableReference(
String tableExpression,
String identificationVariable,

View File

@ -19,6 +19,13 @@ import static org.hibernate.internal.util.StringHelper.isEmpty;
public class UnionTableReference extends NamedTableReference {
private final String[] subclassTableSpaceExpressions;
public UnionTableReference(
String unionTableExpression,
String[] subclassTableSpaceExpressions,
String identificationVariable) {
this( unionTableExpression, subclassTableSpaceExpressions, identificationVariable, false );
}
public UnionTableReference(
String unionTableExpression,
String[] subclassTableSpaceExpressions,

View File

@ -0,0 +1,207 @@
package org.hibernate.orm.test.inheritance.repeatedtable;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.annotations.DiscriminatorOptions;
import org.hibernate.cfg.Configuration;
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
import org.junit.Test;
import jakarta.persistence.*;
import java.util.List;
import static jakarta.persistence.CascadeType.ALL;
import static jakarta.persistence.InheritanceType.JOINED;
import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertTrue;
import static org.hibernate.cfg.AvailableSettings.FORMAT_SQL;
import static org.hibernate.cfg.AvailableSettings.SHOW_SQL;
public class RepeatedTableTest extends BaseCoreFunctionalTestCase {
@Override
protected Class[] getAnnotatedClasses() {
return new Class[]{
DataType.class,
ObjectType.class,
SimpleType.class,
Prop.class
};
}
@Override
protected void configure(Configuration configuration) {
super.configure(configuration);
configuration.setProperty(SHOW_SQL, Boolean.toString(true));
configuration.setProperty(FORMAT_SQL, Boolean.toString(true));
}
@Test
public void test_append_properties() {
Long id;
Long sId;
try (Session sess = openSession()) {
Transaction tx = sess.beginTransaction();
SimpleType simpleType = new SimpleType();
simpleType.setName("simple");
simpleType.setCount(69);
sess.persist(simpleType);
sId = simpleType.getId();
ObjectType objectType = new ObjectType();
objectType.setName("name");
sess.persist(objectType);
id = objectType.getId();
tx.commit();
}
try (Session sess = openSession()) {
Transaction tx = sess.beginTransaction();
ObjectType objectType = sess.find(ObjectType.class, id);
Prop property = new Prop();
property.setName("Prop1");
property.setObjectType(objectType);
objectType.getProperties().add(property);
tx.commit();
}
try (Session sess = openSession()) {
Transaction tx = sess.beginTransaction();
ObjectType objectType = sess.find(ObjectType.class, id);
assertEquals(1, objectType.getProperties().size());
tx.commit();
}
try (Session sess = openSession()) {
DataType dataType1 = sess.find(DataType.class, sId);
assertTrue( dataType1 instanceof SimpleType );
DataType dataType2 = sess.find(DataType.class, id);
assertTrue( dataType2 instanceof ObjectType );
}
try (Session sess = openSession()) {
SimpleType simpleType = sess.find(SimpleType.class, sId);
}
try (Session sess = openSession()) {
assertEquals( 2, sess.createQuery("from RepeatedTableTest$DataType").getResultList().size() );
assertEquals( 1, sess.createQuery("from RepeatedTableTest$ObjectType").getResultList().size() );
assertEquals( 1, sess.createQuery("from RepeatedTableTest$SimpleType").getResultList().size() );
}
}
@Entity
@Table(name = "DATA_TYPE")
@Inheritance(strategy = JOINED)
@DiscriminatorColumn(name = "supertype_id")
@DiscriminatorOptions(force = true)
public static abstract class DataType {
private Long id;
private String name;
@Id
@Column(name = "ID")
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
@Entity
@DiscriminatorValue("8")
@Table(name = "OBJ_TYPE")
@PrimaryKeyJoinColumn(name = "TYPE_ID")
public static class ObjectType extends DataType {
private String description;
private List<Prop> properties;
@Column(name = "desc")
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
@OneToMany(mappedBy = "objectType", cascade = ALL, orphanRemoval = true)
public List<Prop> getProperties() {
return properties;
}
public void setProperties(List<Prop> properties) {
this.properties = properties;
}
}
@Entity
@Table(name = "PROP")
public static class Prop {
private Long id;
private String name;
private ObjectType objectType;
@Id
@Column(name = "ID")
@GeneratedValue
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Column(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@JoinColumn(name = "OBJ_TYPE_ID")
@ManyToOne
public ObjectType getObjectType() {
return objectType;
}
public void setObjectType(ObjectType objectType) {
this.objectType = objectType;
}
}
@Entity
@DiscriminatorValue("2")
@Table(name = "DATA_TYPE")
public static class SimpleType extends DataType {
Integer count;
public Integer getCount() {
return count;
}
public void setCount(Integer count) {
this.count = count;
}
}
}