diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java index db30647614..166606edb6 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSelectBuilder.java @@ -432,8 +432,6 @@ public class LoaderSelectBuilder { } final List fetches = new ArrayList<>(); - String fullPath = fetchParent.getNavigablePath().getFullPath(); - final BiConsumer processor = createFetchableBiConsumer( fetchParent, querySpec, creationState, fetches ); final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java index 5c4c3b43d4..f65af6b211 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/PluralAttributeMapping.java @@ -11,6 +11,7 @@ import java.util.function.Consumer; import org.hibernate.loader.ast.spi.Loadable; import org.hibernate.metamodel.mapping.ordering.OrderByFragment; import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; @@ -56,5 +57,5 @@ public interface PluralAttributeMapping String getSeparateCollectionTable(); - String getBidirectionalPropertyName(); + boolean isBidirectionalAttributeName(NavigablePath fetchablePath); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java index 5d950feec5..302cce2c07 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/PluralAttributeMappingImpl.java @@ -98,7 +98,8 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme private final FetchStyle fetchStyle; private final CascadeStyle cascadeStyle; - private final String bidirectionalPropertyName; + private final String bidirectionalAttributeName; + private final Boolean isInverse; private final CollectionPersister collectionDescriptor; private final String separateCollectionTable; @@ -175,7 +176,9 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme this.cascadeStyle = cascadeStyle; this.collectionDescriptor = collectionDescriptor; - this.bidirectionalPropertyName = StringHelper.subStringNullIfEmpty( bootDescriptor.getMappedByProperty(), '.'); + this.bidirectionalAttributeName = StringHelper.subStringNullIfEmpty( bootDescriptor.getMappedByProperty(), '.'); + + this.isInverse = bootDescriptor.isInverse(); this.sqlAliasStem = SqlAliasStemHelper.INSTANCE.generateStemFromAttributeName( attributeName ); @@ -222,6 +225,17 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme } } + @Override + public boolean isBidirectionalAttributeName(NavigablePath fetchablePath) { + if ( isInverse ) { + return true; + } + if ( bidirectionalAttributeName == null ) { + return false; + } + return fetchablePath.getFullPath().endsWith( bidirectionalAttributeName ); + } + @SuppressWarnings("unused") public void finishInitialization( Property bootProperty, @@ -393,11 +407,6 @@ public class PluralAttributeMappingImpl extends AbstractAttributeMapping impleme return separateCollectionTable; } - @Override - public String getBidirectionalPropertyName() { - return bidirectionalPropertyName; - } - @Override public int getStateArrayPosition() { return stateArrayPosition; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java index 4a3cc1b56c..a94483ac66 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/ToOneAttributeMapping.java @@ -76,7 +76,7 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping private final boolean referringPrimaryKey; private final Cardinality cardinality; - private String bidirectionalPropertyName; + private String bidirectionalAttributeName; private ForeignKeyDescriptor foreignKeyDescriptor; private ForeignKeyDirection foreignKeyDirection; @@ -170,18 +170,11 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping the the navigable path is NavigablePath(Card.fields.{element}.{id}.card) and it does not contain the "primaryKey" part so in ored to recognize the bidirectionality the "primaryKey." is removed from the otherSidePropertyName value. */ - - String mappedByProperty = StringHelper.subStringNullIfEmpty( + // todo (6.0): find a better solution for the embeddable part name not in the NavigablePath + bidirectionalAttributeName = StringHelper.subStringNullIfEmpty( ( (OneToOne) bootValue ).getMappedByProperty(), '.' ); - - if ( mappedByProperty == null ) { - bidirectionalPropertyName = StringHelper.subStringNullIfEmpty( referencedPropertyName, '.' ); - } - else { - bidirectionalPropertyName = mappedByProperty; - } } this.navigableRole = navigableRole; @@ -230,19 +223,19 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping final AssociationKey associationKey = foreignKeyDescriptor.getAssociationKey(); if ( creationState.isAssociationKeyVisited( associationKey ) ) { - NavigablePath parent = fetchablePath.getParent(); - ModelPart modelPart = creationState.resolveModelPart( parent ); + NavigablePath parentNavigablePath = fetchablePath.getParent(); + ModelPart modelPart = creationState.resolveModelPart( parentNavigablePath ); if ( modelPart instanceof EmbeddedIdentifierMappingImpl ) { - while ( parent.getFullPath().endsWith( EntityIdentifierMapping.ROLE_LOCAL_NAME ) ) { - parent = parent.getParent(); + while ( parentNavigablePath.getFullPath().endsWith( EntityIdentifierMapping.ROLE_LOCAL_NAME ) ) { + parentNavigablePath = parentNavigablePath.getParent(); } } while ( modelPart instanceof EmbeddableValuedFetchable ) { - parent = parent.getParent(); - modelPart = creationState.resolveModelPart( parent ); + parentNavigablePath = parentNavigablePath.getParent(); + modelPart = creationState.resolveModelPart( parentNavigablePath ); } - if ( this.bidirectionalPropertyName != null && parent.getFullPath().endsWith( this.bidirectionalPropertyName ) ) { + if ( isBidirectionalAttributeName( parentNavigablePath ) ) { /* class Child { @OneToOne(mappedBy = "biologicalChild") @@ -261,7 +254,7 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping return createCircularBiDirectionalFetch( fetchablePath, fetchParent, - parent.getParent(), + parentNavigablePath, LockMode.READ ); } @@ -269,8 +262,13 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping /* check if mappedBy is on the other side of the association */ - final String otherSideMappedBy = getOthrerSideMappedBy( modelPart, parent.getParent(), creationState ); - if ( otherSideMappedBy != null ) { + final boolean isBiDirectional = isBidirectional( + modelPart, + parentNavigablePath.getParent(), + fetchablePath, + creationState + ); + if ( isBiDirectional ) { /* class Child { @OneToOne(mappedBy = "biologicalChild") @@ -287,15 +285,12 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping otherSideMappedBy = "biologicalChild" */ - - if ( fetchablePath.getFullPath().endsWith( otherSideMappedBy ) ) { - return createCircularBiDirectionalFetch( - fetchablePath, - fetchParent, - parent.getParent(), - LockMode.READ - ); - } + return createCircularBiDirectionalFetch( + fetchablePath, + fetchParent, + parentNavigablePath, + LockMode.READ + ); } /* class Child { @@ -329,37 +324,53 @@ public class ToOneAttributeMapping extends AbstractSingularAttributeMapping return null; } - private String getOthrerSideMappedBy( + private boolean isBidirectional( ModelPart modelPart, NavigablePath parentOfParent, + NavigablePath fetchablePath, DomainResultCreationState creationState) { if ( modelPart instanceof ToOneAttributeMapping ) { - return ( (ToOneAttributeMapping) modelPart ).getBidirectionalPropertyName(); + return ( (ToOneAttributeMapping) modelPart ).isBidirectionalAttributeName( fetchablePath ); } if ( modelPart instanceof PluralAttributeMapping ) { - return ( (PluralAttributeMapping) modelPart ).getBidirectionalPropertyName(); + return ( (PluralAttributeMapping) modelPart ).isBidirectionalAttributeName( fetchablePath ); } if ( modelPart instanceof EntityCollectionPart ) { if ( parentOfParent.getFullPath().endsWith( EntityIdentifierMapping.ROLE_LOCAL_NAME ) ) { parentOfParent = parentOfParent.getParent(); } - return ( (PluralAttributeMapping) creationState.resolveModelPart( parentOfParent ) ).getBidirectionalPropertyName(); + return ( (PluralAttributeMapping) creationState.resolveModelPart( parentOfParent ) ).isBidirectionalAttributeName( + fetchablePath ); } - return null; + return false; } - public String getBidirectionalPropertyName(){ - return bidirectionalPropertyName; + protected boolean isBidirectionalAttributeName(NavigablePath fetchablePath) { + if ( bidirectionalAttributeName == null ) { + return false; + } + return fetchablePath.getFullPath().endsWith( bidirectionalAttributeName ); + } + + public String getBidirectionalAttributeName(){ + return bidirectionalAttributeName; } private Fetch createCircularBiDirectionalFetch( NavigablePath fetchablePath, FetchParent fetchParent, - NavigablePath referencedNavigablePath, + NavigablePath parentNavigablePath, LockMode lockMode) { + NavigablePath referencedNavigablePath; + if ( parentNavigablePath.getParent() == null ) { + referencedNavigablePath = parentNavigablePath; + } + else { + referencedNavigablePath = parentNavigablePath.getParent(); + } return new CircularBiDirectionalFetchImpl( FetchTiming.IMMEDIATE, fetchablePath, diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 3e27a75a3c..f7c466dc76 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -531,10 +531,10 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { if ( persistentClass.isPolymorphic() ) { subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() ); - int initialCapacity = subclassSpan + 1; + final int initialCapacity = CollectionHelper.determineProperSizing( subclassSpan + 1 ); discriminatorValuesByTableName = new LinkedHashMap<>( initialCapacity ); discriminatorColumnNameByTableName = new LinkedHashMap<>( initialCapacity ); - subclassNameByTableName = CollectionHelper.mapOfSize( initialCapacity ); + subclassNameByTableName = new HashMap<>( initialCapacity ); // We need to convert the `discriminatorSQLString` (which is a String read from boot-mapping) into // the type indicated by `#discriminatorType` (String -> Integer, e.g.). try { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchByUniqueKeyInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchByUniqueKeyInitializer.java index fff0928081..95d4b2cfd3 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchByUniqueKeyInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntitySelectFetchByUniqueKeyInitializer.java @@ -43,7 +43,7 @@ public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchIn return; } final String entityName = concreteDescriptor.getEntityName(); - String uniqueKeyPropertyName = fetchedAttribute.getBidirectionalPropertyName(); + String uniqueKeyPropertyName = fetchedAttribute.getBidirectionalAttributeName(); final SharedSessionContractImplementor session = rowProcessingState.getSession(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java index 5057b6c3a3..e3319f6481 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/StandardRowReader.java @@ -15,6 +15,7 @@ import org.hibernate.sql.results.LoadingLogger; import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.collection.CollectionInitializer; +import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchInitializer; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; @@ -155,7 +156,17 @@ public class StandardRowReader implements RowReader { } for ( int i = 0; i < numberOfInitializers; i++ ) { - initializers.get( i ).resolveInstance( rowProcessingState ); + Initializer initializer = initializers.get( i ); + if ( !( initializer instanceof EntityDelayedFetchInitializer ) ) { + initializer.resolveInstance( rowProcessingState ); + } + } + + for ( int i = 0; i < numberOfInitializers; i++ ) { + Initializer initializer = initializers.get( i ); + if ( initializer instanceof EntityDelayedFetchInitializer ) { + initializer.resolveInstance( rowProcessingState ); + } } for ( int i = 0; i < numberOfInitializers; i++ ) {