From 37ec41d319a2de54910b587bf7cb8298097b0c82 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 15 Dec 2022 12:50:29 +0100 Subject: [PATCH] HHH-15879 Introduce a fetchable key for Fetchable within FetchableContainer --- .../ast/internal/AbstractNaturalIdLoader.java | 7 +- .../internal/DatabaseSnapshotExecutor.java | 3 +- .../ast/internal/LoaderSelectBuilder.java | 9 +- .../internal/LoaderSqlAstCreationState.java | 9 +- .../mapping/BasicEntityIdentifierMapping.java | 4 + .../mapping/CompositeIdentifierMapping.java | 5 + .../mapping/EntityDiscriminatorMapping.java | 5 + .../NonAggregatedIdentifierMapping.java | 5 + .../mapping/PluralAttributeMapping.java | 5 + .../internal/AbstractAttributeMapping.java | 9 +- .../internal/AbstractEmbeddableMapping.java | 5 + .../AbstractEntityCollectionPart.java | 5 + .../AbstractSingularAttributeMapping.java | 6 +- .../AbstractStateArrayContributorMapping.java | 5 +- .../internal/AnyDiscriminatorPart.java | 17 +- .../mapping/internal/AnyKeyPart.java | 17 +- .../internal/BasicAttributeMapping.java | 3 + .../internal/BasicValuedCollectionPart.java | 5 + .../CollectionIdentifierDescriptorImpl.java | 5 + .../internal/CompoundNaturalIdMapping.java | 48 ++--- ...criminatedAssociationAttributeMapping.java | 4 + .../DiscriminatedAssociationMapping.java | 21 ++- .../internal/DiscriminatedCollectionPart.java | 5 + .../internal/EmbeddableMappingTypeImpl.java | 5 + .../internal/EmbeddedAttributeMapping.java | 5 + .../internal/EmbeddedCollectionPart.java | 5 + .../internal/EntityVersionMappingImpl.java | 5 + .../mapping/internal/IdClassEmbeddable.java | 1 + .../internal/MappingModelCreationHelper.java | 9 + .../internal/PluralAttributeMappingImpl.java | 3 +- .../internal/SimpleForeignKeyDescriptor.java | 5 + .../internal/ToOneAttributeMapping.java | 5 + .../VirtualEmbeddedAttributeMapping.java | 4 + .../AbstractCollectionPersister.java | 3 +- .../entity/AbstractEntityPersister.java | 46 ++++- .../ImmutableAttributeMappingList.java | 7 + ...mousTupleBasicEntityIdentifierMapping.java | 2 +- .../AnonymousTupleBasicValuedModelPart.java | 10 +- ...onymousTupleEmbeddableValuedModelPart.java | 10 +- ...sTupleEmbeddedEntityIdentifierMapping.java | 3 +- .../AnonymousTupleEntityValuedModelPart.java | 5 +- ...eNonAggregatedEntityIdentifierMapping.java | 3 +- .../AnonymousTupleTableGroupProducer.java | 29 ++- .../derived/CteTupleTableGroupProducer.java | 3 +- .../DomainResultCreationStateImpl.java | 168 ++++++++++-------- .../query/results/ResultSetMappingImpl.java | 22 +-- .../results/complete/EntityResultImpl.java | 81 +++------ .../dynamic/DynamicFetchBuilderLegacy.java | 4 +- .../dynamic/DynamicFetchBuilderStandard.java | 5 +- .../DynamicResultBuilderEntityStandard.java | 5 +- .../ImplicitFetchBuilderEmbeddable.java | 4 +- .../implicit/ImplicitFetchBuilderEntity.java | 8 +- .../sqm/sql/BaseSqmToSqlAstConverter.java | 13 +- .../results/graph/AbstractFetchParent.java | 53 +++--- .../graph/DomainResultCreationState.java | 47 ++++- .../graph/DomainResultGraphPrinter.java | 10 +- .../sql/results/graph/FetchList.java | 83 +++++++++ .../sql/results/graph/FetchParent.java | 9 +- .../sql/results/graph/Fetchable.java | 12 ++ .../sql/results/graph/FetchableContainer.java | 7 + .../internal/CollectionDomainResult.java | 15 +- .../internal/EagerCollectionFetch.java | 26 ++- .../AggregateEmbeddableResultImpl.java | 7 +- .../EmbeddableExpressionResultImpl.java | 21 +-- .../internal/EmbeddableResultImpl.java | 7 +- .../entity/AbstractEntityResultGraphNode.java | 33 +--- .../AbstractNonJoinedEntityFetch.java | 15 +- .../graph/internal/ImmutableFetchList.java | 141 +++++++++++++++ .../spi/ScrollableResultsConsumer.java | 14 +- .../ast/CriteriaEntityGraphTest.java | 10 +- .../ast/EntityGraphLoadPlanBuilderTest.java | 8 +- .../entitygraph/ast/HqlEntityGraphTest.java | 8 +- .../entitygraph/ast/LoadPlanBuilderTest.java | 8 +- .../orm/test/loading/MappedFetchTests.java | 9 +- 74 files changed, 851 insertions(+), 377 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchList.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/internal/ImmutableFetchList.java diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractNaturalIdLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractNaturalIdLoader.java index b760a72bed..4e57891c6e 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractNaturalIdLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/AbstractNaturalIdLoader.java @@ -56,6 +56,7 @@ import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.spi.ListResultsConsumer; import org.hibernate.stat.spi.StatisticsImplementor; @@ -413,12 +414,12 @@ public abstract class AbstractNaturalIdLoader implements NaturalIdLoader { return results.get( 0 ); } - private static List visitFetches( + private static ImmutableFetchList visitFetches( FetchParent fetchParent, LoaderSqlAstCreationState creationState) { final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer(); final int size = fetchableContainer.getNumberOfFetchables(); - final List fetches = new ArrayList<>( size ); + final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchableContainer ); for ( int i = 0; i < size; i++ ) { final Fetchable fetchable = fetchableContainer.getFetchable( i ); final NavigablePath navigablePath = fetchParent.resolveNavigablePath( fetchable ); @@ -432,6 +433,6 @@ public abstract class AbstractNaturalIdLoader implements NaturalIdLoader { ); fetches.add( fetch ); } - return fetches; + return fetches.build(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java index f44609ec10..6689ef7e1d 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/DatabaseSnapshotExecutor.java @@ -41,6 +41,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect; import org.hibernate.sql.exec.spi.JdbcParameterBindings; import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.internal.RowTransformerDatabaseSnapshotImpl; import org.hibernate.sql.results.spi.ListResultsConsumer; import org.hibernate.type.BasicType; @@ -76,7 +77,7 @@ class DatabaseSnapshotExecutor { sqlAliasBaseManager, new FromClauseIndex( null ), LockOptions.NONE, - (fetchParent, creationState) -> Collections.emptyList(), + (fetchParent, creationState) -> ImmutableFetchList.EMPTY, true, sessionFactory ); 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 17c4a09679..c7ae496f38 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 @@ -83,6 +83,7 @@ import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.collection.internal.CollectionDomainResult; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl; @@ -648,12 +649,12 @@ public class LoaderSelectBuilder { orderByFragments.add( new AbstractMap.SimpleEntry<>( orderByFragment, tableGroup ) ); } - private List visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState) { + private ImmutableFetchList visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState) { if ( log.isTraceEnabled() ) { log.tracef( "Starting visitation of FetchParent's Fetchables : %s", fetchParent.getNavigablePath() ); } - final List fetches = new ArrayList<>(); + final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchParent.getReferencedMappingContainer() ); final BiConsumer processor = createFetchableBiConsumer( fetchParent, creationState, @@ -671,13 +672,13 @@ public class LoaderSelectBuilder { for ( int i = 0; i < size; i++ ) { processor.accept( referencedMappingContainer.getFetchable( i ), false ); } - return fetches; + return fetches.build(); } private BiConsumer createFetchableBiConsumer( FetchParent fetchParent, LoaderSqlAstCreationState creationState, - List fetches) { + ImmutableFetchList.Builder fetches) { return (fetchable, isKeyFetchable) -> { final NavigablePath fetchablePath; diff --git a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java index fb0a01c490..7d1e6d1799 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/ast/internal/LoaderSqlAstCreationState.java @@ -38,6 +38,7 @@ import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; /** * Helper used when generating the database-snapshot select query @@ -45,7 +46,7 @@ import org.hibernate.sql.results.graph.FetchParent; public class LoaderSqlAstCreationState implements SqlAstQueryPartProcessingState, SqlAstCreationState, DomainResultCreationState, QueryOptions { public interface FetchProcessor { - List visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState); + ImmutableFetchList visitFetches(FetchParent fetchParent, LoaderSqlAstCreationState creationState); } private final SqlAliasBaseManager sqlAliasBaseManager; @@ -119,15 +120,15 @@ public class LoaderSqlAstCreationState } @Override - public List visitFetches(FetchParent fetchParent) { + public ImmutableFetchList visitFetches(FetchParent fetchParent) { return fetchProcessor.visitFetches( fetchParent, this ); } @Override - public List visitNestedFetches(FetchParent fetchParent) { + public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) { final FetchParent nestingFetchParent = processingState.getNestingFetchParent(); processingState.setNestingFetchParent( fetchParent ); - final List fetches = fetchProcessor.visitFetches( fetchParent, this ); + final ImmutableFetchList fetches = fetchProcessor.visitFetches( fetchParent, this ); processingState.setNestingFetchParent( nestingFetchParent ); return fetches; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicEntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicEntityIdentifierMapping.java index cfc6c11ecb..ceae81e67b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicEntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/BasicEntityIdentifierMapping.java @@ -14,4 +14,8 @@ import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping * @author Steve Ebersole */ public interface BasicEntityIdentifierMapping extends SingleAttributeIdentifierMapping, BasicValuedModelPart { + @Override + default int getFetchableKey() { + return -1; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/CompositeIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/CompositeIdentifierMapping.java index 32a67ecb78..2c5416b1f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/CompositeIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/CompositeIdentifierMapping.java @@ -16,6 +16,11 @@ import org.hibernate.engine.spi.IdentifierValue; */ public interface CompositeIdentifierMapping extends EntityIdentifierMapping, EmbeddableValuedModelPart { + @Override + default int getFetchableKey() { + return -1; + } + @Override default IdentifierValue getUnsavedStrategy() { return IdentifierValue.UNDEFINED; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityDiscriminatorMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityDiscriminatorMapping.java index ffecfe39de..d44bb799d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityDiscriminatorMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityDiscriminatorMapping.java @@ -42,6 +42,11 @@ public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValue return getPartName(); } + @Override + default int getFetchableKey() { + return -2; + } + DiscriminatorType getDiscriminatorType(); String getConcreteEntityNameForDiscriminatorValue(Object value); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NonAggregatedIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NonAggregatedIdentifierMapping.java index a6fcebe28d..7cc6284336 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NonAggregatedIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/NonAggregatedIdentifierMapping.java @@ -45,6 +45,11 @@ public interface NonAggregatedIdentifierMapping extends CompositeIdentifierMappi */ IdentifierValueMapper getIdentifierValueMapper(); + @Override + default int getFetchableKey() { + return -1; + } + /** * Think of an AttributeConverter for id values to account for representation * difference between virtual and id-class mappings 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 009d314bb8..a5f9c2fea1 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 @@ -99,6 +99,11 @@ public interface PluralAttributeMapping return 1; } + @Override + default int getNumberOfFetchableKeys() { + return getNumberOfKeyFetchables() + getNumberOfFetchables(); + } + @Override default void visitFetchables(IndexedConsumer fetchableConsumer, EntityMappingType treatTargetType) { fetchableConsumer.accept( 0, getElementDescriptor() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractAttributeMapping.java index 768ce33c85..0c2ce944da 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractAttributeMapping.java @@ -17,11 +17,13 @@ import org.hibernate.type.descriptor.java.JavaType; */ public abstract class AbstractAttributeMapping implements AttributeMapping { private final String name; + private final int fetchableIndex; private final ManagedMappingType declaringType; - public AbstractAttributeMapping(String name, ManagedMappingType declaringType) { + public AbstractAttributeMapping(String name, int fetchableIndex, ManagedMappingType declaringType) { this.name = name; + this.fetchableIndex = fetchableIndex; this.declaringType = declaringType; } @@ -35,6 +37,11 @@ public abstract class AbstractAttributeMapping implements AttributeMapping { return name; } + @Override + public int getFetchableKey() { + return fetchableIndex; + } + @Override public MappingType getPartMappingType() { return getMappedType(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEmbeddableMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEmbeddableMapping.java index 8cff39e186..14fbf2f420 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEmbeddableMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEmbeddableMapping.java @@ -300,6 +300,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType bootPropertyDescriptor.getName(), navigableRole.append( bootPropertyDescriptor.getName() ), attributeIndex, + attributeIndex, bootPropertyDescriptor, declarer, (BasicType) subtype, @@ -380,6 +381,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType typeConfiguration.getJavaTypeRegistry().getDescriptor( Object.class ), declarer, attributeIndex, + attributeIndex, attributeMetadataAccess, bootPropertyDescriptor.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE, propertyAccess, @@ -407,6 +409,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType attributeMapping = MappingModelCreationHelper.buildEmbeddedAttributeMapping( bootPropertyDescriptor.getName(), attributeIndex, + attributeIndex, bootPropertyDescriptor, declarer, subCompositeType, @@ -426,6 +429,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType attributeMapping = MappingModelCreationHelper.buildPluralAttributeMapping( bootPropertyDescriptor.getName(), attributeIndex, + attributeIndex, bootPropertyDescriptor, entityPersister, propertyAccess, @@ -442,6 +446,7 @@ public abstract class AbstractEmbeddableMapping implements EmbeddableMappingType bootPropertyDescriptor.getName(), navigableRole.append( bootPropertyDescriptor.getName() ), attributeIndex, + attributeIndex, bootPropertyDescriptor, entityPersister, entityPersister, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityCollectionPart.java index 734d4f7599..8e5d0b5fec 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityCollectionPart.java @@ -114,6 +114,11 @@ public abstract class AbstractEntityCollectionPart implements EntityCollectionPa return nature.getName(); } + @Override + public int getFetchableKey() { + return nature == Nature.INDEX || !collectionDescriptor.hasIndex() ? 0 : 1; + } + @Override public EntityMappingType getAssociatedEntityMappingType() { return associatedEntityTypeDescriptor; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractSingularAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractSingularAttributeMapping.java index f8f2fb3614..08378bcda2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractSingularAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractSingularAttributeMapping.java @@ -27,23 +27,25 @@ public abstract class AbstractSingularAttributeMapping public AbstractSingularAttributeMapping( String name, int stateArrayPosition, + int fetchableIndex, AttributeMetadata attributeMetadata, FetchOptions mappedFetchOptions, ManagedMappingType declaringType, PropertyAccess propertyAccess) { - super( name, attributeMetadata, mappedFetchOptions, stateArrayPosition, declaringType ); + super( name, attributeMetadata, mappedFetchOptions, stateArrayPosition, fetchableIndex, declaringType ); this.propertyAccess = propertyAccess; } public AbstractSingularAttributeMapping( String name, int stateArrayPosition, + int fetchableIndex, AttributeMetadata attributeMetadata, FetchTiming fetchTiming, FetchStyle fetchStyle, ManagedMappingType declaringType, PropertyAccess propertyAccess) { - super( name, attributeMetadata, fetchTiming, fetchStyle, stateArrayPosition, declaringType ); + super( name, attributeMetadata, fetchTiming, fetchStyle, stateArrayPosition, fetchableIndex, declaringType ); this.propertyAccess = propertyAccess; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractStateArrayContributorMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractStateArrayContributorMapping.java index bfdc2be92d..c21de11458 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractStateArrayContributorMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractStateArrayContributorMapping.java @@ -30,8 +30,9 @@ public abstract class AbstractStateArrayContributorMapping FetchTiming fetchTiming, FetchStyle fetchStyle, int stateArrayPosition, + int fetchableIndex, ManagedMappingType declaringType) { - super( name, declaringType ); + super( name, fetchableIndex, declaringType ); this.attributeMetadata = attributeMetadata; this.fetchTiming = fetchTiming; this.fetchStyle = fetchStyle; @@ -43,6 +44,7 @@ public abstract class AbstractStateArrayContributorMapping AttributeMetadata attributeMetadata, FetchOptions mappedFetchOptions, int stateArrayPosition, + int fetchableIndex, ManagedMappingType declaringType) { this( name, @@ -50,6 +52,7 @@ public abstract class AbstractStateArrayContributorMapping mappedFetchOptions.getTiming(), mappedFetchOptions.getStyle(), stateArrayPosition, + fetchableIndex, declaringType ); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java index 259563b6e4..ef03371638 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyDiscriminatorPart.java @@ -59,8 +59,8 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, private final Integer precision; private final Integer scale; - private boolean isInsertable; - private boolean isUpdateable; + private final boolean insertable; + private final boolean updateable; private final MetaType metaType; public AnyDiscriminatorPart( @@ -83,8 +83,8 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, this.length = length; this.precision = precision; this.scale = scale; - this.isInsertable = insertable; - this.isUpdateable = updateable; + this.insertable = insertable; + this.updateable = updateable; this.metaType = metaType; } @@ -118,12 +118,12 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, @Override public boolean isInsertable() { - return isInsertable; + return insertable; } @Override public boolean isUpdateable() { - return isUpdateable; + return updateable; } @Override @@ -235,6 +235,11 @@ public class AnyDiscriminatorPart implements BasicValuedModelPart, FetchOptions, return getPartName(); } + @Override + public int getFetchableKey() { + return 0; + } + @Override public FetchOptions getMappedFetchOptions() { return this; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java index 7b00bba531..4ea793ebb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AnyKeyPart.java @@ -54,8 +54,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { private final Integer precision; private final Integer scale; private final boolean nullable; - private boolean isInsertable; - private boolean isUpdateable; + private final boolean insertable; + private final boolean updateable; private final JdbcMapping jdbcMapping; public AnyKeyPart( @@ -80,8 +80,8 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { this.precision = precision; this.scale = scale; this.nullable = nullable; - this.isInsertable = insertable; - this.isUpdateable = updateable; + this.insertable = insertable; + this.updateable = updateable; this.jdbcMapping = jdbcMapping; } @@ -107,12 +107,12 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { @Override public boolean isInsertable() { - return isInsertable; + return insertable; } @Override public boolean isUpdateable() { - return isUpdateable; + return updateable; } @Override @@ -180,6 +180,11 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions { return getPartName(); } + @Override + public int getFetchableKey() { + return 1; + } + @Override public FetchOptions getMappedFetchOptions() { return this; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java index cfa0c1a296..72daefe1dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicAttributeMapping.java @@ -69,6 +69,7 @@ public class BasicAttributeMapping String attributeName, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, AttributeMetadata attributeMetadata, FetchTiming mappedFetchTiming, FetchStyle mappedFetchStyle, @@ -91,6 +92,7 @@ public class BasicAttributeMapping super( attributeName, stateArrayPosition, + fetchableIndex, attributeMetadata, mappedFetchTiming, mappedFetchStyle, @@ -155,6 +157,7 @@ public class BasicAttributeMapping attributeName, original.getNavigableRole(), stateArrayPosition, + original.getFetchableKey(), attributeMetadata, FetchTiming.IMMEDIATE, FetchStyle.JOIN, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java index f85ab3fce0..8534ea73f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/BasicValuedCollectionPart.java @@ -232,6 +232,11 @@ public class BasicValuedCollectionPart return nature.getName(); } + @Override + public int getFetchableKey() { + return nature == Nature.INDEX || !collectionDescriptor.hasIndex() ? 0 : 1; + } + @Override public FetchOptions getMappedFetchOptions() { return this; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java index fffa73e0de..91997e0597 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CollectionIdentifierDescriptorImpl.java @@ -206,6 +206,11 @@ public class CollectionIdentifierDescriptorImpl implements CollectionIdentifierD return null; } + @Override + public int getFetchableKey() { + return -1; + } + @Override public FetchOptions getMappedFetchOptions() { return this; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java index 66b26e5a3b..e5ffd0cf69 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/CompoundNaturalIdMapping.java @@ -8,7 +8,6 @@ package org.hibernate.metamodel.mapping.internal; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.function.BiConsumer; @@ -19,7 +18,6 @@ import org.hibernate.NotYetImplementedFor6Exception; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.loader.ast.internal.CompoundNaturalIdLoader; import org.hibernate.loader.ast.internal.MultiNaturalIdLoaderStandard; import org.hibernate.loader.ast.spi.MultiNaturalIdLoader; @@ -48,6 +46,7 @@ import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.entity.EntityInitializer; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.type.descriptor.java.JavaType; @@ -453,7 +452,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement private final CompoundNaturalIdMapping naturalIdMapping; private final JavaType arrayJtd; - private final List fetches; + private final ImmutableFetchList fetches; + private final boolean hasJoinFetches; + private final boolean containsCollectionFetches; private final String resultVariable; @@ -468,7 +469,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement this.arrayJtd = arrayJtd; this.resultVariable = resultVariable; - this.fetches = Collections.unmodifiableList( creationState.visitFetches( this ) ); + this.fetches = creationState.visitFetches( this ); + this.hasJoinFetches = this.fetches.hasJoinFetches(); + this.containsCollectionFetches = this.fetches.containsCollectionFetches(); } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -517,22 +520,24 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement } @Override - public List getFetches() { + public ImmutableFetchList getFetches() { return fetches; } @Override public Fetch findFetch(Fetchable fetchable) { assert fetchable != null; + return fetches.get( fetchable ); + } - for ( int i = 0; i < fetches.size(); i++ ) { - final Fetch fetch = fetches.get( i ); - if ( fetchable.equals( fetch.getFetchedMapping() ) ) { - return fetch; - } - } + @Override + public boolean hasJoinFetches() { + return hasJoinFetches; + } - return null; + @Override + public boolean containsCollectionFetches() { + return containsCollectionFetches; } } @@ -541,10 +546,10 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement private final CompoundNaturalIdMapping naturalIdMapping; private final JavaType jtd; - private final List> subAssemblers; + private final DomainResultAssembler[] subAssemblers; private AssemblerImpl( - List fetches, + ImmutableFetchList fetches, NavigablePath navigablePath, CompoundNaturalIdMapping naturalIdMapping, JavaType jtd, @@ -557,11 +562,10 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement // we just "need it" as an impl detail for handling Fetches final InitializerImpl initializer = new InitializerImpl( navigablePath, naturalIdMapping ); - this.subAssemblers = CollectionHelper.arrayList( fetches.size() ); - for ( int i = 0; i < fetches.size(); i++ ) { - final Fetch fetch = fetches.get( i ); - final DomainResultAssembler fetchAssembler = fetch.createAssembler( initializer, creationState ); - subAssemblers.add( fetchAssembler ); + this.subAssemblers = new DomainResultAssembler[fetches.size()]; + int i = 0; + for ( Fetch fetch : fetches ) { + subAssemblers[i++] = fetch.createAssembler( initializer, creationState ); } } @@ -569,9 +573,9 @@ public class CompoundNaturalIdMapping extends AbstractNaturalIdMapping implement public Object[] assemble( RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) { - final Object[] result = new Object[ subAssemblers.size() ]; - for ( int i = 0; i < subAssemblers.size(); i++ ) { - result[ i ] = subAssemblers.get( i ).assemble( rowProcessingState, options ); + final Object[] result = new Object[ subAssemblers.length ]; + for ( int i = 0; i < subAssemblers.length; i++ ) { + result[ i ] = subAssemblers[i].assemble( rowProcessingState, options ); } return result; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java index 0b81b9877c..da29591ea1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationAttributeMapping.java @@ -71,6 +71,7 @@ public class DiscriminatedAssociationAttributeMapping JavaType baseAssociationJtd, ManagedMappingType declaringType, int stateArrayPosition, + int fetchableIndex, AttributeMetadata attributeMetadata, FetchTiming fetchTiming, PropertyAccess propertyAccess, @@ -81,6 +82,7 @@ public class DiscriminatedAssociationAttributeMapping super( bootProperty.getName(), stateArrayPosition, + fetchableIndex, attributeMetadata, fetchTiming, FetchStyle.SELECT, @@ -188,8 +190,10 @@ public class DiscriminatedAssociationAttributeMapping public Fetchable getFetchable(int position) { switch ( position ) { case 0: + assert getDiscriminatorPart().getFetchableKey() == 0; return getDiscriminatorPart(); case 1: + assert getKeyPart().getFetchableKey() == 1; return getKeyPart(); } throw new IndexOutOfBoundsException(position); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java index 625963d76b..a1e5545ecf 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedAssociationMapping.java @@ -44,6 +44,7 @@ import org.hibernate.sql.results.graph.FetchOptions; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.Fetchable; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.type.AnyType; @@ -413,7 +414,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption private Fetch discriminatorValueFetch; private Fetch keyValueFetch; - private List fetches; + private ImmutableFetchList fetches; public AnyValuedResultGraphNode( NavigablePath navigablePath, @@ -425,11 +426,11 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption } protected void afterInitialize(DomainResultCreationState creationState) { - this.fetches = Collections.unmodifiableList( creationState.visitFetches( this ) ); + this.fetches = creationState.visitFetches( this ); assert fetches.size() == 2; - discriminatorValueFetch = fetches.get( 0 ); - keyValueFetch = fetches.get( 1 ); + discriminatorValueFetch = fetches.get( graphedPart.getDiscriminatorPart() ); + keyValueFetch = fetches.get( graphedPart.getKeyPart() ); } public Fetch getDiscriminatorValueFetch() { @@ -470,7 +471,7 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption } @Override - public List getFetches() { + public ImmutableFetchList getFetches() { return fetches; } @@ -486,6 +487,16 @@ public class DiscriminatedAssociationMapping implements MappingType, FetchOption throw new IllegalArgumentException( "Given Fetchable [" + fetchable + "] did not match either discriminator nor key mapping" ); } + + @Override + public boolean hasJoinFetches() { + return false; + } + + @Override + public boolean containsCollectionFetches() { + return false; + } } private static class AnyValuedResult extends AnyValuedResultGraphNode implements DomainResult { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java index 926076deb1..9928527c64 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/DiscriminatedCollectionPart.java @@ -117,6 +117,11 @@ public class DiscriminatedCollectionPart implements DiscriminatedAssociationMode return nature.getName(); } + @Override + public int getFetchableKey() { + return nature == Nature.INDEX || !collectionDescriptor.hasIndex() ? 0 : 1; + } + @Override public FetchOptions getMappedFetchOptions() { return discriminatorMapping; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java index f8680c8afb..4d1d5a8b15 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddableMappingTypeImpl.java @@ -407,6 +407,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme bootPropertyDescriptor.getName(), valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ), attributeIndex, + attributeIndex, bootPropertyDescriptor, this, (BasicType) subtype, @@ -488,6 +489,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme typeConfiguration.getJavaTypeRegistry().getDescriptor( Object.class ), this, attributeIndex, + attributeIndex, attributeMetadataAccess, bootPropertyDescriptor.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE, propertyAccess, @@ -515,6 +517,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme attributeMapping = MappingModelCreationHelper.buildEmbeddedAttributeMapping( bootPropertyDescriptor.getName(), attributeIndex, + attributeIndex, bootPropertyDescriptor, this, subCompositeType, @@ -533,6 +536,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme attributeMapping = MappingModelCreationHelper.buildPluralAttributeMapping( bootPropertyDescriptor.getName(), attributeIndex, + attributeIndex, bootPropertyDescriptor, entityPersister, representationStrategy.resolvePropertyAccess( bootPropertyDescriptor ), @@ -548,6 +552,7 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme bootPropertyDescriptor.getName(), valueMapping.getNavigableRole().append( bootPropertyDescriptor.getName() ), attributeIndex, + attributeIndex, bootPropertyDescriptor, entityPersister, entityPersister, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java index 9b0363c266..4e659aa32e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedAttributeMapping.java @@ -75,6 +75,7 @@ public class EmbeddedAttributeMapping String name, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, String tableExpression, AttributeMetadata attributeMetadata, String parentInjectionAttributeName, @@ -87,6 +88,7 @@ public class EmbeddedAttributeMapping name, navigableRole, stateArrayPosition, + fetchableIndex, tableExpression, attributeMetadata, getPropertyAccess( parentInjectionAttributeName, embeddableMappingType ), @@ -102,6 +104,7 @@ public class EmbeddedAttributeMapping String name, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, String tableExpression, AttributeMetadata attributeMetadata, PropertyAccess parentInjectionAttributePropertyAccess, @@ -113,6 +116,7 @@ public class EmbeddedAttributeMapping super( name, stateArrayPosition, + fetchableIndex, attributeMetadata, mappedFetchTiming, mappedFetchStyle, @@ -139,6 +143,7 @@ public class EmbeddedAttributeMapping super( inverseModelPart.getFetchableName(), -1, + inverseModelPart.getFetchableKey(), null, inverseModelPart.getMappedFetchOptions(), keyDeclaringType, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java index 7da77f356e..5f69d18b1a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EmbeddedCollectionPart.java @@ -140,6 +140,11 @@ public class EmbeddedCollectionPart implements CollectionPart, EmbeddableValuedF return getNature().getName(); } + @Override + public int getFetchableKey() { + return nature == Nature.INDEX || !collectionDescriptor.hasIndex() ? 0 : 1; + } + @Override public FetchOptions getMappedFetchOptions() { return this; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java index df811ad8f5..6b127466fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/EntityVersionMappingImpl.java @@ -207,6 +207,11 @@ public class EntityVersionMappingImpl implements EntityVersionMapping, FetchOpti return attributeName; } + @Override + public int getFetchableKey() { + return getVersionAttribute().getFetchableKey(); + } + @Override public FetchOptions getMappedFetchOptions() { return this; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/IdClassEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/IdClassEmbeddable.java index a016c50901..86d8dc8e9e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/IdClassEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/IdClassEmbeddable.java @@ -107,6 +107,7 @@ public class IdClassEmbeddable extends AbstractEmbeddableMapping implements Iden .append( EntityIdentifierMapping.ROLE_LOCAL_NAME ) .append( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ), -1, + -1, idTable, attributeMetadata, (PropertyAccess) null, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java index dc29744e23..1b7481e0dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/MappingModelCreationHelper.java @@ -178,6 +178,7 @@ public class MappingModelCreationHelper { String attrName, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, Property bootProperty, ManagedMappingType declaringType, BasicType attrType, @@ -223,6 +224,7 @@ public class MappingModelCreationHelper { attrName, navigableRole, stateArrayPosition, + fetchableIndex, attributeMetadata, fetchTiming, fetchStyle, @@ -249,6 +251,7 @@ public class MappingModelCreationHelper { public static EmbeddedAttributeMapping buildEmbeddedAttributeMapping( String attrName, int stateArrayPosition, + int fetchableIndex, Property bootProperty, ManagedMappingType declaringType, CompositeType attrType, @@ -280,6 +283,7 @@ public class MappingModelCreationHelper { attrName, declaringType.getNavigableRole().append( attrName ), stateArrayPosition, + fetchableIndex, tableExpression, attributeMetadataAccess, component.getParentProperty(), @@ -295,6 +299,7 @@ public class MappingModelCreationHelper { attrName, declaringType.getNavigableRole().append( attrName ), stateArrayPosition, + fetchableIndex, tableExpression, attributeMetadataAccess, component.getParentProperty(), @@ -373,6 +378,7 @@ public class MappingModelCreationHelper { public static PluralAttributeMapping buildPluralAttributeMapping( String attrName, int stateArrayPosition, + int fetchableIndex, Property bootProperty, ManagedMappingType declaringType, PropertyAccess propertyAccess, @@ -578,6 +584,7 @@ public class MappingModelCreationHelper { attributeMetadata, collectionMappingType, stateArrayPosition, + fetchableIndex, elementDescriptor, indexDescriptor, identifierDescriptor, @@ -1492,6 +1499,7 @@ public class MappingModelCreationHelper { String attrName, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, Property bootProperty, ManagedMappingType declaringType, EntityPersister declaringEntityPersister, @@ -1546,6 +1554,7 @@ public class MappingModelCreationHelper { attrName, navigableRole, stateArrayPosition, + fetchableIndex, (ToOne) bootProperty.getValue(), attributeMetadata, fetchTiming, 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 d0711aae9d..79ea5a0336 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 @@ -119,6 +119,7 @@ public class PluralAttributeMappingImpl AttributeMetadata attributeMetadata, CollectionMappingType collectionMappingType, int stateArrayPosition, + int fetchableIndex, CollectionPart elementDescriptor, CollectionPart indexDescriptor, CollectionIdentifierDescriptor identifierDescriptor, @@ -127,7 +128,7 @@ public class PluralAttributeMappingImpl CascadeStyle cascadeStyle, ManagedMappingType declaringType, CollectionPersister collectionDescriptor) { - super( attributeName, declaringType ); + super( attributeName, fetchableIndex, declaringType ); this.propertyAccess = propertyAccess; this.attributeMetadata = attributeMetadata; this.collectionMappingType = collectionMappingType; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java index 26fb8c9464..4b2282266c 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/SimpleForeignKeyDescriptor.java @@ -581,6 +581,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa return PART_NAME; } + @Override + public int getFetchableKey() { + throw new UnsupportedOperationException(); + } + @Override public FetchOptions getMappedFetchOptions() { return this; 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 01c1032fb8..024778e247 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 @@ -160,6 +160,7 @@ public class ToOneAttributeMapping String name, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, ToOne bootValue, AttributeMetadata attributeMetadata, FetchOptions mappedFetchOptions, @@ -171,6 +172,7 @@ public class ToOneAttributeMapping name, navigableRole, stateArrayPosition, + fetchableIndex, bootValue, attributeMetadata, mappedFetchOptions.getTiming(), @@ -186,6 +188,7 @@ public class ToOneAttributeMapping String name, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, ToOne bootValue, AttributeMetadata attributeMetadata, FetchTiming mappedFetchTiming, @@ -197,6 +200,7 @@ public class ToOneAttributeMapping super( name, stateArrayPosition, + fetchableIndex, attributeMetadata, adjustFetchTiming( mappedFetchTiming, bootValue ), mappedFetchStyle, @@ -548,6 +552,7 @@ public class ToOneAttributeMapping super( original.getAttributeName(), original.getStateArrayPosition(), + original.getFetchableKey(), original.getAttributeMetadata(), original, declaringType, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/VirtualEmbeddedAttributeMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/VirtualEmbeddedAttributeMapping.java index bb855e0a38..b0f4795512 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/VirtualEmbeddedAttributeMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/VirtualEmbeddedAttributeMapping.java @@ -27,6 +27,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im String name, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, String tableExpression, AttributeMetadata attributeMetadata, String parentInjectionAttributeName, @@ -39,6 +40,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im name, navigableRole, stateArrayPosition, + fetchableIndex, tableExpression, attributeMetadata, parentInjectionAttributeName, @@ -54,6 +56,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im String name, NavigableRole navigableRole, int stateArrayPosition, + int fetchableIndex, String tableExpression, AttributeMetadata attributeMetadata, PropertyAccess parentInjectionAttributePropertyAccess, @@ -66,6 +69,7 @@ public class VirtualEmbeddedAttributeMapping extends EmbeddedAttributeMapping im name, navigableRole, stateArrayPosition, + fetchableIndex, tableExpression, attributeMetadata, parentInjectionAttributePropertyAccess, diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 10fa331e9a..fb9af49779 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -125,6 +125,7 @@ import org.hibernate.sql.model.internal.TableDeleteStandard; import org.hibernate.sql.model.jdbc.JdbcDeleteMutation; import org.hibernate.sql.model.jdbc.JdbcMutationOperation; import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.generator.Generator; import org.hibernate.generator.InMemoryGenerator; @@ -934,7 +935,7 @@ public abstract class AbstractCollectionPersister new SqlAliasBaseManager(), new SimpleFromClauseAccessImpl(), LockOptions.NONE, - (fetchParent, creationState) -> new ArrayList<>(), + (fetchParent, creationState) -> ImmutableFetchList.EMPTY, true, getFactory() ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 2cbab87d66..2906df180f 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -261,6 +261,7 @@ import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.tuple.NonIdentifierAttribute; @@ -1797,10 +1798,10 @@ public abstract class AbstractEntityPersister return expression; } - private List fetchProcessor(FetchParent fetchParent, LoaderSqlAstCreationState creationState) { + private ImmutableFetchList fetchProcessor(FetchParent fetchParent, LoaderSqlAstCreationState creationState) { final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer(); final int size = fetchableContainer.getNumberOfFetchables(); - final List fetches = new ArrayList<>( size ); + final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchableContainer ); for ( int i = 0; i < size; i++ ) { final Fetchable fetchable = fetchableContainer.getFetchable( i ); @@ -1848,7 +1849,7 @@ public abstract class AbstractEntityPersister } } - return fetches; + return fetches.build(); } private boolean isSelectable(FetchParent fetchParent, Fetchable fetchable) { @@ -4652,6 +4653,7 @@ public abstract class AbstractEntityPersister final NonIdentifierAttribute[] properties = currentEntityMetamodel.getProperties(); AttributeMappingsMap.Builder mappingsBuilder = AttributeMappingsMap.builder(); + int fetchableIndex = getFetchableIndexOffset(); for ( int i = 0; i < currentEntityMetamodel.getPropertySpan(); i++ ) { final NonIdentifierAttribute runtimeAttrDefinition = properties[i]; final Property bootProperty = bootEntityDescriptor.getProperty( runtimeAttrDefinition.getName() ); @@ -4664,6 +4666,7 @@ public abstract class AbstractEntityPersister runtimeAttrDefinition, bootProperty, stateArrayPosition++, + fetchableIndex++, creationProcess ) ); @@ -4701,6 +4704,7 @@ public abstract class AbstractEntityPersister } final ImmutableAttributeMappingList.Builder builder = new ImmutableAttributeMappingList.Builder( attributeMappings.size() ); visitSubTypeAttributeMappings( attributeMapping -> builder.add( attributeMapping ) ); + assert superMappingType != null || builder.assertFetchableIndexes(); staticFetchableList = builder.build(); return true; } @@ -4767,6 +4771,30 @@ public abstract class AbstractEntityPersister } } + private int getFetchableIndexOffset() { + if ( superMappingType != null ) { + final EntityMappingType rootEntityDescriptor = getRootEntityDescriptor(); + int offset = rootEntityDescriptor.getNumberOfDeclaredAttributeMappings(); + for ( EntityMappingType subMappingType : rootEntityDescriptor.getSubMappingTypes() ) { + if ( subMappingType == this ) { + break; + } + // Determining the number of attribute mappings unfortunately has to be done this way, + // because calling `subMappingType.getNumberOfDeclaredAttributeMappings()` at this point + // may produce wrong results because subMappingType might not have completed prepareMappingModel yet + final int propertySpan = subMappingType.getEntityPersister().getEntityMetamodel().getPropertySpan(); + final int superPropertySpan = subMappingType.getSuperMappingType() + .getEntityPersister() + .getEntityMetamodel() + .getPropertySpan(); + final int numberOfDeclaredAttributeMappings = propertySpan - superPropertySpan; + offset += numberOfDeclaredAttributeMappings; + } + return offset; + } + return 0; + } + private void prepareMappingModel(MappingModelCreationProcess creationProcess, PersistentClass bootEntityDescriptor) { final EntityInstantiator instantiator = getRepresentationStrategy().getInstantiator(); final Supplier templateInstanceCreator; @@ -5206,6 +5234,7 @@ public abstract class AbstractEntityPersister NonIdentifierAttribute tupleAttrDefinition, Property bootProperty, int stateArrayPosition, + int fetchableIndex, MappingModelCreationProcess creationProcess) { final SessionFactoryImplementor sessionFactory = creationProcess.getCreationContext().getSessionFactory(); final JdbcServices jdbcServices = sessionFactory.getJdbcServices(); @@ -5229,6 +5258,7 @@ public abstract class AbstractEntityPersister attrName, getNavigableRole().append( bootProperty.getName() ), stateArrayPosition, + fetchableIndex, bootProperty, this, (BasicType) attrType, @@ -5318,6 +5348,7 @@ public abstract class AbstractEntityPersister attrName, getNavigableRole().append( bootProperty.getName() ), stateArrayPosition, + fetchableIndex, bootProperty, this, (BasicType) attrType, @@ -5362,6 +5393,7 @@ public abstract class AbstractEntityPersister baseAssociationJtd, this, stateArrayPosition, + fetchableIndex, attributeMetadataAccess, bootProperty.isLazy() ? FetchTiming.DELAYED : FetchTiming.IMMEDIATE, propertyAccess, @@ -5375,6 +5407,7 @@ public abstract class AbstractEntityPersister return MappingModelCreationHelper.buildEmbeddedAttributeMapping( attrName, stateArrayPosition, + fetchableIndex, bootProperty, this, (CompositeType) attrType, @@ -5389,6 +5422,7 @@ public abstract class AbstractEntityPersister return MappingModelCreationHelper.buildPluralAttributeMapping( attrName, stateArrayPosition, + fetchableIndex, bootProperty, this, propertyAccess, @@ -5402,6 +5436,7 @@ public abstract class AbstractEntityPersister attrName, getNavigableRole().append( attrName ), stateArrayPosition, + fetchableIndex, bootProperty, this, this, @@ -5659,6 +5694,11 @@ public abstract class AbstractEntityPersister return getStaticFetchableList().size(); } + @Override + public int getNumberOfFetchableKeys() { + return superMappingType == null ? getNumberOfFetchables() : getRootEntityDescriptor().getNumberOfFetchables(); + } + @Override public int getNumberOfKeyFetchables() { return 0; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/internal/ImmutableAttributeMappingList.java b/hibernate-core/src/main/java/org/hibernate/persister/internal/ImmutableAttributeMappingList.java index 249169473e..d6e5bace1e 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/internal/ImmutableAttributeMappingList.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/internal/ImmutableAttributeMappingList.java @@ -90,6 +90,13 @@ public final class ImmutableAttributeMappingList implements AttributeMappingsLis return new ImmutableAttributeMappingList( builderList ); } + public boolean assertFetchableIndexes() { + for ( int i = 0; i < builderList.size(); i++ ) { + final AttributeMapping attributeMapping = builderList.get( i ); + assert i == attributeMapping.getFetchableKey(); + } + return true; + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicEntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicEntityIdentifierMapping.java index 23894451e4..6e750871b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicEntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicEntityIdentifierMapping.java @@ -29,7 +29,7 @@ public class AnonymousTupleBasicEntityIdentifierMapping SqmExpressible expressible, JdbcMapping jdbcMapping, BasicEntityIdentifierMapping delegate) { - super( delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping ); + super( delegate.getAttributeName(), selectionExpression, expressible, jdbcMapping, -1 ); this.delegate = delegate; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicValuedModelPart.java index ae10fd0c4f..28ee17703a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleBasicValuedModelPart.java @@ -47,16 +47,19 @@ public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingTyp private final String selectionExpression; private final SqmExpressible expressible; private final JdbcMapping jdbcMapping; + private final int fetchableIndex; public AnonymousTupleBasicValuedModelPart( String partName, String selectionExpression, SqmExpressible expressible, - JdbcMapping jdbcMapping) { + JdbcMapping jdbcMapping, + int fetchableIndex) { this.partName = partName; this.selectionExpression = selectionExpression; this.expressible = expressible; this.jdbcMapping = jdbcMapping; + this.fetchableIndex = fetchableIndex; } @Override @@ -164,6 +167,11 @@ public class AnonymousTupleBasicValuedModelPart implements ModelPart, MappingTyp return partName; } + @Override + public int getFetchableKey() { + return fetchableIndex; + } + @Override public FetchOptions getMappedFetchOptions() { return FETCH_OPTIONS; diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java index 94590b658f..112810b5e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddableValuedModelPart.java @@ -73,16 +73,19 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued private final DomainType domainType; private final String componentName; private final EmbeddableValuedModelPart existingModelPartContainer; + private final int fetchableIndex; public AnonymousTupleEmbeddableValuedModelPart( Map modelParts, DomainType domainType, String componentName, - EmbeddableValuedModelPart existingModelPartContainer) { + EmbeddableValuedModelPart existingModelPartContainer, + int fetchableIndex) { this.modelParts = modelParts; this.domainType = domainType; this.componentName = componentName; this.existingModelPartContainer = existingModelPartContainer; + this.fetchableIndex = fetchableIndex; } @Override @@ -321,6 +324,11 @@ public class AnonymousTupleEmbeddableValuedModelPart implements EmbeddableValued return getPartName(); } + @Override + public int getFetchableKey() { + return fetchableIndex; + } + @Override public FetchOptions getMappedFetchOptions() { return FETCH_OPTIONS; diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddedEntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddedEntityIdentifierMapping.java index 1bca9e1dc0..f19ce941a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddedEntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEmbeddedEntityIdentifierMapping.java @@ -37,7 +37,8 @@ public class AnonymousTupleEmbeddedEntityIdentifierMapping extends AnonymousTupl modelParts, domainType, componentName, - (EmbeddableValuedModelPart) delegate + (EmbeddableValuedModelPart) delegate, + -1 ); this.delegate = delegate; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java index 318c48dbb4..02f8ca8402 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleEntityValuedModelPart.java @@ -82,12 +82,14 @@ public class AnonymousTupleEntityValuedModelPart private final String componentName; private final EntityValuedModelPart delegate; private final Set targetKeyPropertyNames; + private final int fetchableIndex; public AnonymousTupleEntityValuedModelPart( EntityIdentifierMapping identifierMapping, DomainType domainType, String componentName, - EntityValuedModelPart delegate) { + EntityValuedModelPart delegate, + int fetchableIndex) { this.identifierMapping = identifierMapping; this.domainType = domainType; this.componentName = componentName; @@ -103,6 +105,7 @@ public class AnonymousTupleEntityValuedModelPart persister.getFactory() ); this.targetKeyPropertyNames = targetKeyPropertyNames; + this.fetchableIndex = fetchableIndex; } public ModelPart getForeignKeyPart() { diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleNonAggregatedEntityIdentifierMapping.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleNonAggregatedEntityIdentifierMapping.java index a375243a4b..392594b727 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleNonAggregatedEntityIdentifierMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleNonAggregatedEntityIdentifierMapping.java @@ -38,7 +38,8 @@ public class AnonymousTupleNonAggregatedEntityIdentifierMapping extends Anonymou modelParts, domainType, componentName, - delegate + delegate, + -1 ); this.delegate = delegate; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleTableGroupProducer.java b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleTableGroupProducer.java index bc6ea4f675..0fddae54c4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleTableGroupProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/AnonymousTupleTableGroupProducer.java @@ -98,7 +98,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map partName, partName, tableGroup == null ? null : getModelPart( tableGroup ), - compatibleTableExpressions + compatibleTableExpressions, + modelParts.size() ); } else { @@ -108,7 +109,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map selectableNode.getExpressible(), sqlSelection.getExpressionType() .getJdbcMappings() - .get( 0 ) + .get( 0 ), + modelParts.size() ); } modelParts.put( partName, modelPart ); @@ -136,7 +138,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map String selectionExpression, String partName, ModelPart existingModelPart, - Set compatibleTableExpressions) { + Set compatibleTableExpressions, + int fetchableIndex) { if ( domainType instanceof EntityDomainType ) { final EntityValuedModelPart existingModelPartContainer = (EntityValuedModelPart) existingModelPart; final EntityIdentifierMapping identifierMapping = existingModelPartContainer.getEntityMappingType() @@ -149,6 +152,7 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map final Set> attributes = (Set>) ( (ManagedDomainType) ( (EntityDomainType) domainType ).getIdentifierDescriptor().getSqmPathType() ).getAttributes(); final Map modelParts = CollectionHelper.linkedMapOfSize( attributes.size() ); final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) identifierMapping; + int index = 0; for ( Attribute attribute : attributes ) { if ( !( attribute instanceof SingularPersistentAttribute ) ) { throw new IllegalArgumentException( "Only embeddables without collections are supported!" ); @@ -162,7 +166,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map selectionExpression + "_" + attributeName + "_" + attribute.getName(), attribute.getName(), modelPartContainer.findSubPart( attribute.getName(), null ), - compatibleTableExpressions + compatibleTableExpressions, + index++ ); modelParts.put( modelPart.getPartName(), modelPart ); } @@ -190,6 +195,7 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map final Set> attributes = (Set>) ( (ManagedDomainType) ( (EntityDomainType) domainType ).getIdentifierDescriptor().getSqmPathType() ).getAttributes(); final Map modelParts = CollectionHelper.linkedMapOfSize( attributes.size() ); final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) identifierMapping; + int index = 0; for ( Attribute attribute : attributes ) { if ( !( attribute instanceof SingularPersistentAttribute ) ) { throw new IllegalArgumentException( "Only embeddables without collections are supported!" ); @@ -203,7 +209,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map selectionExpression + "_" + attribute.getName(), attribute.getName(), modelPartContainer.findSubPart( attribute.getName(), null ), - compatibleTableExpressions + compatibleTableExpressions, + index++ ); modelParts.put( modelPart.getPartName(), modelPart ); } @@ -222,7 +229,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map newIdentifierMapping, domainType, selectionExpression, - existingModelPartContainer + existingModelPartContainer, + fetchableIndex ); } else if ( domainType instanceof ManagedDomainType ) { @@ -230,6 +238,7 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map final Set> attributes = (Set>) ( (ManagedDomainType) domainType ).getAttributes(); final Map modelParts = CollectionHelper.linkedMapOfSize( attributes.size() ); final EmbeddableValuedModelPart modelPartContainer = (EmbeddableValuedModelPart) existingModelPart; + int index = 0; for ( Attribute attribute : attributes ) { if ( !( attribute instanceof SingularPersistentAttribute ) ) { throw new IllegalArgumentException( "Only embeddables without collections are supported" ); @@ -243,11 +252,12 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map selectionExpression + "_" + attribute.getName(), attribute.getName(), modelPartContainer.findSubPart( attribute.getName(), null ), - compatibleTableExpressions + compatibleTableExpressions, + index++ ); modelParts.put( modelPart.getPartName(), modelPart ); } - return new AnonymousTupleEmbeddableValuedModelPart( modelParts, domainType, selectionExpression, modelPartContainer ); + return new AnonymousTupleEmbeddableValuedModelPart( modelParts, domainType, selectionExpression, modelPartContainer, fetchableIndex ); } else { return new AnonymousTupleBasicValuedModelPart( @@ -257,7 +267,8 @@ public class AnonymousTupleTableGroupProducer implements TableGroupProducer, Map sqlSelections.get( selectionIndex ) .getExpressionType() .getJdbcMappings() - .get( 0 ) + .get( 0 ), + fetchableIndex ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/derived/CteTupleTableGroupProducer.java b/hibernate-core/src/main/java/org/hibernate/query/derived/CteTupleTableGroupProducer.java index 82b3b331ed..cf1360afdc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/derived/CteTupleTableGroupProducer.java +++ b/hibernate-core/src/main/java/org/hibernate/query/derived/CteTupleTableGroupProducer.java @@ -59,7 +59,8 @@ public class CteTupleTableGroupProducer extends AnonymousTupleTableGroupProducer attributeName, attributeName, basicType, - basicType + basicType, + -1 ); } return null; diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java index 476641d3f9..c97803d23f 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/DomainResultCreationStateImpl.java @@ -8,7 +8,6 @@ package org.hibernate.query.results; import java.util.AbstractMap; import java.util.HashMap; -import java.util.List; import java.util.Map; import java.util.function.Consumer; import java.util.function.Function; @@ -17,7 +16,6 @@ import org.hibernate.Internal; import org.hibernate.LockMode; import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.internal.util.collections.Stack; import org.hibernate.internal.util.collections.StandardStack; import org.hibernate.metamodel.mapping.Association; @@ -51,6 +49,8 @@ import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; +import org.hibernate.sql.results.graph.entity.EntityResultGraphNode; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.spi.TypeConfiguration; @@ -126,9 +126,8 @@ public class DomainResultCreationStateImpl return jdbcResultsMetadata; } - public NavigablePath getCurrentRelativePath() { - final Map.Entry entry = relativePathStack.getCurrent(); - return entry == null ? null : entry.getValue(); + public Map.Entry getCurrentRelativePath() { + return relativePathStack.getCurrent(); } public void pushExplicitFetchMementoResolver(Function resolver) { @@ -332,26 +331,106 @@ public class DomainResultCreationStateImpl } @Override - public List visitNestedFetches(FetchParent fetchParent) { + public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) { final FetchParent oldNestingFetchParent = this.nestingFetchParent; this.nestingFetchParent = fetchParent; - final List fetches = visitFetches( fetchParent ); + final ImmutableFetchList fetches = visitFetches( fetchParent ); this.nestingFetchParent = oldNestingFetchParent; return fetches; } @Override - public List visitFetches(FetchParent fetchParent) { + public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) { + final EntityValuedModelPart entityValuedFetchable = fetchParent.getEntityValuedModelPart(); + final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping(); + final String identifierAttributeName = attributeName( identifierMapping ); + final Map.Entry oldEntry = relativePathStack.getCurrent(); + final String fullPath; + if ( identifierMapping instanceof NonAggregatedIdentifierMapping ) { + fullPath = oldEntry == null ? "" : oldEntry.getKey(); + } + else { + fullPath = oldEntry == null ? + identifierAttributeName : + oldEntry.getKey() + "." + identifierAttributeName; + } + + final Fetchable fetchable = (Fetchable) identifierMapping; + final FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack + .getCurrent() + .apply( fullPath ); + DynamicFetchBuilderLegacy fetchBuilderLegacy; + if ( explicitFetchBuilder == null ) { + fetchBuilderLegacy = legacyFetchResolver.resolve( + fromClauseAccess.findTableGroup( fetchParent.getNavigablePath() ) + .getPrimaryTableReference() + .getIdentificationVariable(), + identifierAttributeName + ); + } + else { + fetchBuilderLegacy = null; + } + + final EntityIdentifierNavigablePath fetchPath = new EntityIdentifierNavigablePath( + fetchParent.getNavigablePath(), + identifierAttributeName + ); + + final boolean processingKeyFetches = this.processingKeyFetches; + this.processingKeyFetches = true; + if ( identifierMapping instanceof CompositeIdentifierMapping ) { + relativePathStack.push( new AbstractMap.SimpleEntry<>( fullPath, fetchPath ) ); + } + + try { + final FetchBuilder fetchBuilder; + if ( explicitFetchBuilder != null ) { + fetchBuilder = explicitFetchBuilder; + } + else { + if ( fetchBuilderLegacy == null ) { + fetchBuilder = Builders.implicitFetchBuilder( fetchPath, fetchable, this ); + } + else { + fetchBuilder = fetchBuilderLegacy; + } + } + return fetchBuilder.buildFetch( + fetchParent, + fetchPath, + jdbcResultsMetadata, + (s, s2) -> { + throw new UnsupportedOperationException(); + }, + this + ); + } + finally { + this.processingKeyFetches = processingKeyFetches; + if ( identifierMapping instanceof CompositeIdentifierMapping ) { + this.relativePathStack.pop(); + } + } + } + + @Override + public ImmutableFetchList visitFetches(FetchParent fetchParent) { final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer(); + final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( fetchableContainer ); + final Consumer fetchableConsumer = createFetchableConsumer( fetchParent, fetches ); + fetchableContainer.visitKeyFetchables( fetchableConsumer, null ); + fetchableContainer.visitFetchables( fetchableConsumer, null ); + return fetches.build(); + } - final List fetches = CollectionHelper.arrayList( fetchableContainer.getNumberOfFetchables() ); - - final Consumer fetchableConsumer = fetchable -> { + private Consumer createFetchableConsumer(FetchParent fetchParent, ImmutableFetchList.Builder fetches) { + return fetchable -> { final String fetchableName = fetchable.getFetchableName(); Map.Entry currentEntry; if ( relativePathStack.isEmpty() ) { currentEntry = new AbstractMap.SimpleEntry<>( - getRelativePath( "", fetchable, fetchableContainer ), + getRelativePath( "", fetchable ), new NavigablePath( fetchableName ) ); } @@ -359,7 +438,7 @@ public class DomainResultCreationStateImpl final Map.Entry oldEntry = relativePathStack.getCurrent(); final String key = oldEntry.getKey(); currentEntry = new AbstractMap.SimpleEntry<>( - getRelativePath( key, fetchable, fetchableContainer ), + getRelativePath( key, fetchable ), oldEntry.getValue().append( fetchableName ) ); } @@ -384,8 +463,9 @@ public class DomainResultCreationStateImpl final Association association = (Association) fetchable; final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor(); - final String partName = attributeName( foreignKeyDescriptor.getSide( association.getSideNature().inverse() ) - .getModelPart()); + final String partName = attributeName( + foreignKeyDescriptor.getSide( association.getSideNature().inverse() ).getModelPart() + ); // If there are no fetch builders for this association, we only want to fetch the FK if ( explicitFetchBuilder == null && fetchBuilderLegacy == null && partName != null ) { @@ -438,65 +518,9 @@ public class DomainResultCreationStateImpl } }; - - boolean previous = this.processingKeyFetches; - this.processingKeyFetches = true; - - if ( fetchableContainer instanceof EntityValuedModelPart ) { - final EntityValuedModelPart entityValuedFetchable = (EntityValuedModelPart) fetchableContainer; - final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping(); - final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMapping; - final String identifierAttributeName = attributeName( identifierMapping ); - if ( idClass ) { - final Map.Entry oldEntry = relativePathStack.getCurrent(); - relativePathStack.push( - new AbstractMap.SimpleEntry<>( - oldEntry == null ? "" : oldEntry.getKey(), - new EntityIdentifierNavigablePath( - oldEntry == null ? fetchParent.getNavigablePath() : oldEntry.getValue(), - identifierAttributeName - ) - ) - ); - } - else if ( identifierMapping instanceof CompositeIdentifierMapping ) { - final Map.Entry oldEntry = relativePathStack.getCurrent(); - relativePathStack.push( - new AbstractMap.SimpleEntry<>( - oldEntry == null ? - identifierAttributeName : - oldEntry.getKey() + "." + identifierAttributeName, - new EntityIdentifierNavigablePath( - oldEntry == null ? fetchParent.getNavigablePath() : oldEntry.getValue(), - identifierAttributeName - ) - ) - ); - } - - try { - if ( identifierMapping instanceof FetchableContainer ) { - // essentially means the entity has a composite id - ask the embeddable to visit its fetchables - ( (FetchableContainer) identifierMapping ).visitFetchables( fetchableConsumer, null ); - } - else { - fetchableConsumer.accept( (Fetchable) identifierMapping ); - } - } - finally { - this.processingKeyFetches = previous; - if ( idClass ) { - this.relativePathStack.pop(); - } - } - } - - fetchableContainer.visitKeyFetchables( fetchableConsumer, null ); - fetchableContainer.visitFetchables( fetchableConsumer, null ); - return fetches; } - private String getRelativePath(String oldEntry, Fetchable fetchable, FetchableContainer fetchableContainer) { + private String getRelativePath(String oldEntry, Fetchable fetchable) { if ( fetchable instanceof AttributeMapping || fetchable instanceof SingleAttributeIdentifierMapping || fetchable instanceof BasicValuedCollectionPart ) { if ( !oldEntry.equals( "" ) ) { return oldEntry + '.' + fetchable.getFetchableName(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java index e21d389a18..f10e4a901a 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/ResultSetMappingImpl.java @@ -36,6 +36,7 @@ import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; import org.hibernate.sql.results.graph.entity.EntityResult; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -248,7 +249,7 @@ public class ResultSetMappingImpl implements ResultSetMapping { // otherwise we assume that even if there are duplicate aliases, the values are equivalent. // If we don't do that, there is no way to fetch joined inheritance entities if ( polymorphic && ( legacyFetchBuilders == null || legacyFetchBuilders.isEmpty() ) - && !hasJoinFetches( entityResult.getFetches() ) ) { + && !entityResult.hasJoinFetches() ) { final Set aliases = new TreeSet<>( String.CASE_INSENSITIVE_ORDER ); final AbstractEntityPersister entityPersister = (AbstractEntityPersister) entityResult.getReferencedMappingContainer() .getEntityPersister(); @@ -305,25 +306,6 @@ public class ResultSetMappingImpl implements ResultSetMapping { } } - private static boolean hasJoinFetches(List fetches) { - for ( int i = 0; i < fetches.size(); i++ ) { - final Fetch fetch = fetches.get( i ); - if ( fetch instanceof BasicFetch || fetch.getTiming() == FetchTiming.DELAYED ) { - // That's fine - } - else if ( fetch instanceof EmbeddableResultGraphNode ) { - // Check all these fetches as well - if ( hasJoinFetches( ( (EmbeddableResultGraphNode) fetch ).getFetches() ) ) { - return true; - } - } - else { - return true; - } - } - return false; - } - private DomainResult makeImplicitDomainResult( int valuesArrayPosition, Consumer sqlSelectionConsumer, diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/EntityResultImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/EntityResultImpl.java index 1f2a557234..96387a1a2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/EntityResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/EntityResultImpl.java @@ -6,19 +6,11 @@ */ package org.hibernate.query.results.complete; -import java.util.Collections; -import java.util.List; import java.util.function.Function; import org.hibernate.LockMode; -import org.hibernate.engine.FetchTiming; -import org.hibernate.internal.util.MutableObject; -import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityValuedModelPart; -import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping; -import org.hibernate.spi.EntityIdentifierNavigablePath; import org.hibernate.spi.NavigablePath; -import org.hibernate.query.results.ResultsHelper; import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResultAssembler; @@ -28,10 +20,10 @@ import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.basic.BasicFetch; -import org.hibernate.sql.results.graph.entity.EntityInitializer; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.entity.internal.EntityAssembler; import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; /** * @author Steve Ebersole @@ -42,12 +34,13 @@ public class EntityResultImpl implements EntityResult { private final Fetch identifierFetch; private final BasicFetch discriminatorFetch; - private final List fetches; + private final ImmutableFetchList fetches; + private final boolean hasJoinFetches; + private final boolean containsCollectionFetches; private final String resultAlias; private final LockMode lockMode; - @SuppressWarnings( { "PointlessNullCheck" } ) public EntityResultImpl( NavigablePath navigablePath, EntityValuedModelPart entityValuedModelPart, @@ -78,49 +71,12 @@ public class EntityResultImpl implements EntityResult { } ); + this.identifierFetch = creationState.visitIdentifierFetch( this ); this.discriminatorFetch = discriminatorFetchBuilder.apply( this ); - final List localFetches = creationState.visitFetches( this ); - - final EntityIdentifierMapping identifierMapping = entityValuedModelPart - .getEntityMappingType() - .getIdentifierMapping(); - final String idAttributeName = identifierMapping instanceof SingleAttributeIdentifierMapping - ? ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName() - : null; - - final MutableObject idFetchRef = new MutableObject<>(); - - for ( int i = 0; i < localFetches.size(); i++ ) { - final Fetch fetch = localFetches.get( i ); - final String fetchLocalName = fetch.getNavigablePath().getLocalName(); - - if ( fetchLocalName.equals( EntityIdentifierMapping.ROLE_LOCAL_NAME ) - || ( idAttributeName != null && fetchLocalName.equals( idAttributeName ) ) ) { - // we found the id fetch - idFetchRef.set( fetch ); - localFetches.remove( i ); - break; - } - } - this.fetches = Collections.unmodifiableList( localFetches ); - - if ( idFetchRef.isNotSet() ) { - identifierFetch = ( (Fetchable) identifierMapping ).generateFetch( - this, - new EntityIdentifierNavigablePath( - navigablePath, - ResultsHelper.attributeName( identifierMapping ) - ), - FetchTiming.IMMEDIATE, - true, - null, - creationState - ); - } - else { - this.identifierFetch = idFetchRef.get(); - } + this.fetches = creationState.visitFetches( this ); + this.hasJoinFetches = fetches.hasJoinFetches(); + this.containsCollectionFetches = fetches.containsCollectionFetches(); } @Override @@ -144,20 +100,23 @@ public class EntityResultImpl implements EntityResult { } @Override - public List getFetches() { + public ImmutableFetchList getFetches() { return fetches; } @Override public Fetch findFetch(Fetchable fetchable) { - final String name = fetchable.getFetchableName(); - for ( int i = 0; i < fetches.size(); i++ ) { - final Fetch fetch = fetches.get( i ); - if ( fetch.getFetchedMapping().getFetchableName().equals( name ) ) { - return fetch; - } - } - return null; + return fetches.get( fetchable ); + } + + @Override + public boolean hasJoinFetches() { + return hasJoinFetches; + } + + @Override + public boolean containsCollectionFetches() { + return containsCollectionFetches; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java index 8d15e93db6..1470047f21 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderLegacy.java @@ -199,13 +199,13 @@ public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQue } } try { - final NavigablePath currentRelativePath = creationState.getCurrentRelativePath(); + final Map.Entry currentRelativePath = creationState.getCurrentRelativePath(); final String prefix; if ( currentRelativePath == null ) { prefix = ""; } else { - prefix = currentRelativePath.getFullPath() + prefix = currentRelativePath.getKey() .replace( ELEMENT_PREFIX, "" ) .replace( INDEX_PREFIX, "" ) + "."; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java index 544b97271c..551a8864eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicFetchBuilderStandard.java @@ -14,13 +14,11 @@ import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.BasicValuedMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.SelectableConsumer; -import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.query.NativeQuery; import org.hibernate.spi.NavigablePath; import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.ResultsHelper; -import org.hibernate.query.results.ResultSetMappingSqlSelection; import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; @@ -28,6 +26,7 @@ import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Fetchable; +import org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey; @@ -114,7 +113,7 @@ public class DynamicFetchBuilderStandard creationStateImpl ); } - else if ( attributeMapping instanceof EmbeddedAttributeMapping ) { + else if ( attributeMapping instanceof EmbeddableValuedFetchable ) { attributeMapping.forEachSelectable( selectableConsumer ); return parent.generateFetchableFetch( attributeMapping, diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java index 485f46a9a5..5374d8051d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/dynamic/DynamicResultBuilderEntityStandard.java @@ -9,6 +9,7 @@ package org.hibernate.query.results.dynamic; import java.util.ArrayList; import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.BiFunction; import java.util.function.Function; @@ -279,13 +280,13 @@ public class DynamicResultBuilderEntityStandard } try { - final NavigablePath currentRelativePath = creationState.getCurrentRelativePath(); + final Map.Entry currentRelativePath = creationState.getCurrentRelativePath(); final String prefix; if ( currentRelativePath == null ) { prefix = ""; } else { - prefix = currentRelativePath.getFullPath() + prefix = currentRelativePath.getKey() .replace( ELEMENT_PREFIX, "" ) .replace( INDEX_PREFIX, "" ) + "."; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java index f2a50c7052..fdd86e2b9b 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEmbeddable.java @@ -51,13 +51,13 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder { this.fetchPath = fetchPath; this.fetchable = fetchable; final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); - final NavigablePath relativePath = creationStateImpl.getCurrentRelativePath(); + final Map.Entry relativePath = creationStateImpl.getCurrentRelativePath(); final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); final int size = fetchable.getNumberOfFetchables(); final Map fetchBuilders = CollectionHelper.linkedMapOfSize( size ); for ( int i = 0; i < size; i++ ) { final Fetchable subFetchable = fetchable.getFetchable( i ); - final NavigablePath subFetchPath = relativePath.append( subFetchable.getFetchableName() ); + final NavigablePath subFetchPath = relativePath.getValue().append( subFetchable.getFetchableName() ); final FetchBuilder explicitFetchBuilder = fetchBuilderResolver.apply( subFetchPath.getFullPath() ); if ( explicitFetchBuilder == null ) { fetchBuilders.put( diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java index e6bad0808b..cbc0a866ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderEntity.java @@ -48,25 +48,25 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder { this.fetchPath = fetchPath; this.fetchable = fetchable; final DomainResultCreationStateImpl creationStateImpl = impl( creationState ); - final NavigablePath relativePath = creationStateImpl.getCurrentRelativePath(); + final Map.Entry relativePath = creationStateImpl.getCurrentRelativePath(); final Function fetchBuilderResolver = creationStateImpl.getCurrentExplicitFetchMementoResolver(); ForeignKeyDescriptor foreignKeyDescriptor = fetchable.getForeignKeyDescriptor(); final String associationKeyPropertyName; final NavigablePath associationKeyFetchPath; if ( fetchable.getReferencedPropertyName() == null ) { associationKeyPropertyName = fetchable.getEntityMappingType().getIdentifierMapping().getPartName(); - associationKeyFetchPath = relativePath.append( associationKeyPropertyName ); + associationKeyFetchPath = relativePath.getValue().append( associationKeyPropertyName ); } else { associationKeyPropertyName = fetchable.getReferencedPropertyName(); - NavigablePath path = relativePath; + NavigablePath path = relativePath.getValue(); for ( String part : associationKeyPropertyName.split( "\\." ) ) { path = path.append( part ); } associationKeyFetchPath = path; } final FetchBuilder explicitAssociationKeyFetchBuilder = fetchBuilderResolver - .apply( associationKeyFetchPath.getFullPath() ); + .apply( relativePath.getKey() + "." + associationKeyPropertyName ); final Map fetchBuilders; if ( explicitAssociationKeyFetchBuilder == null ) { final MappingType partMappingType = foreignKeyDescriptor.getPartMappingType(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java index b2c44bdccd..d89c8b8b55 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/sqm/sql/BaseSqmToSqlAstConverter.java @@ -383,6 +383,7 @@ import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiation; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.sql.results.internal.SqlSelectionImpl; import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl; import org.hibernate.type.BasicType; @@ -7137,7 +7138,7 @@ public abstract class BaseSqmToSqlAstConverter extends Base // .getOrMakeJavaDescriptor( namedClass ); } - public void addFetch(List fetches, FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) { + private void addFetch(ImmutableFetchList.Builder fetches, FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) { final NavigablePath resolvedNavigablePath = fetchParent.resolveNavigablePath( fetchable ); final Map.Entry> sqlSelectionsToTrack = trackedFetchSelectionsForGroup.get( resolvedNavigablePath ); final int sqlSelectionStartIndexForFetch; @@ -7333,28 +7334,28 @@ public abstract class BaseSqmToSqlAstConverter extends Base } @Override - public List visitNestedFetches(FetchParent fetchParent) { + public ImmutableFetchList visitNestedFetches(FetchParent fetchParent) { final SqlAstQueryPartProcessingStateImpl processingState = (SqlAstQueryPartProcessingStateImpl) getCurrentProcessingState(); final FetchParent nestingFetchParent = processingState.getNestingFetchParent(); processingState.setNestingFetchParent( fetchParent ); - final List fetches = visitFetches( fetchParent ); + final ImmutableFetchList fetches = visitFetches( fetchParent ); processingState.setNestingFetchParent( nestingFetchParent ); return fetches; } @Override - public List visitFetches(FetchParent fetchParent) { + public ImmutableFetchList visitFetches(FetchParent fetchParent) { final FetchableContainer referencedMappingContainer = fetchParent.getReferencedMappingContainer(); final int keySize = referencedMappingContainer.getNumberOfKeyFetchables(); final int size = referencedMappingContainer.getNumberOfFetchables(); - final List fetches = CollectionHelper.arrayList( keySize + size ); + final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( referencedMappingContainer ); for ( int i = 0; i < keySize; i++ ) { addFetch( fetches, fetchParent, referencedMappingContainer.getKeyFetchable( i ), true ); } for ( int i = 0; i < size; i++ ) { addFetch( fetches, fetchParent, referencedMappingContainer.getFetchable( i ), false ); } - return fetches; + return fetches.build(); } private boolean shouldExplicitFetch(Integer maxDepth, Fetchable fetchable) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/AbstractFetchParent.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/AbstractFetchParent.java index 976bea6dd9..ac3037b65f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/AbstractFetchParent.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/AbstractFetchParent.java @@ -6,12 +6,9 @@ */ package org.hibernate.sql.results.graph; -import java.util.Collections; -import java.util.List; - import org.hibernate.metamodel.mapping.EntityVersionMapping; -import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.type.descriptor.java.JavaType; /** @@ -21,7 +18,9 @@ public abstract class AbstractFetchParent implements FetchParent { private final FetchableContainer fetchContainer; private final NavigablePath navigablePath; - private List fetches; + private ImmutableFetchList fetches = ImmutableFetchList.EMPTY; + private boolean hasJoinFetches; + private boolean containsCollectionFetches; public AbstractFetchParent(FetchableContainer fetchContainer, NavigablePath navigablePath) { this.fetchContainer = fetchContainer; @@ -29,12 +28,14 @@ public abstract class AbstractFetchParent implements FetchParent { } public void afterInitialize(FetchParent fetchParent, DomainResultCreationState creationState) { - assert fetches == null; + assert fetches == ImmutableFetchList.EMPTY; resetFetches( creationState.visitFetches( fetchParent ) ); } - protected void resetFetches(final List newFetches) { - this.fetches = Collections.unmodifiableList( newFetches ); + protected void resetFetches(ImmutableFetchList newFetches) { + this.fetches = newFetches; + this.hasJoinFetches = newFetches.hasJoinFetches(); + this.containsCollectionFetches = newFetches.containsCollectionFetches(); } public FetchableContainer getFetchContainer() { @@ -57,35 +58,25 @@ public abstract class AbstractFetchParent implements FetchParent { } @Override - public List getFetches() { - return fetches == null ? Collections.emptyList() : fetches; + public ImmutableFetchList getFetches() { + return fetches; } @Override public Fetch findFetch(final Fetchable fetchable) { - if ( fetches == null ) { - return null; - } - - //Iterate twice so we can perform the cheapest checks on each item first: - for ( int i = 0; i < fetches.size(); i++ ) { - final Fetch fetch = fetches.get( i ); - if ( fetchable == fetch.getFetchedMapping() ) { - return fetch; - } - } - if ( fetchable instanceof EntityVersionMapping ) { - //Second iteration performs the slightly more expensive checks, necessary for EntityVersionMapping: - final NavigableRole navigableRole = fetchable.getNavigableRole(); - for ( int i = 0; i < fetches.size(); i++ ) { - final Fetch fetch = fetches.get( i ); - if ( fetch.getFetchedMapping().getNavigableRole().equals( navigableRole ) ) { - return fetch; - } - } + return fetches.get( ( (EntityVersionMapping) fetchable ).getVersionAttribute() ); } + return fetches.get( fetchable ); + } - return null; + @Override + public boolean hasJoinFetches() { + return hasJoinFetches; + } + + @Override + public boolean containsCollectionFetches() { + return containsCollectionFetches; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultCreationState.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultCreationState.java index 516e2bb0ba..5b0691b383 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultCreationState.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultCreationState.java @@ -9,12 +9,22 @@ package org.hibernate.sql.results.graph; import java.util.List; import org.hibernate.Incubating; +import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.AssociationKey; +import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; +import org.hibernate.metamodel.mapping.EntityIdentifierMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.ModelPart; +import org.hibernate.spi.EntityIdentifierNavigablePath; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.ast.spi.SqlAliasBaseManager; import org.hibernate.sql.ast.spi.SqlAstCreationState; +import org.hibernate.sql.results.graph.basic.BasicFetch; +import org.hibernate.sql.results.graph.entity.EntityResultGraphNode; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; + +import static org.hibernate.query.results.ResultsHelper.attributeName; /** * Contains state related to building {@link DomainResult} and @@ -77,6 +87,39 @@ public interface DomainResultCreationState { */ ModelPart resolveModelPart(NavigablePath navigablePath); + default Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) { + final EntityIdentifierMapping identifierMapping = fetchParent.getEntityValuedModelPart() + .getEntityMappingType() + .getIdentifierMapping(); + return fetchParent.generateFetchableFetch( + (Fetchable) identifierMapping, + new EntityIdentifierNavigablePath( fetchParent.getNavigablePath(), attributeName( identifierMapping ) ), + FetchTiming.IMMEDIATE, + true, + null, + this + ); + } + + default BasicFetch visitDiscriminatorFetch(EntityResultGraphNode fetchParent) { + final EntityMappingType entityDescriptor = fetchParent.getEntityValuedModelPart().getEntityMappingType(); + final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); + // No need to fetch the discriminator if this type does not have subclasses + if ( discriminatorMapping != null && entityDescriptor.hasSubclasses() ) { + return discriminatorMapping.generateFetch( + fetchParent, + fetchParent.getNavigablePath().append( EntityDiscriminatorMapping.ROLE_NAME ), + FetchTiming.IMMEDIATE, + true, + null, + this + ); + } + else { + return null; + } + } + /** * Visit fetches for the given parent. * @@ -108,9 +151,9 @@ public interface DomainResultCreationState { * are built/accessed. Comes down to how we'd know whether to join fetch or select fetch. Simply pass * along FetchStyle? */ - List visitFetches(FetchParent fetchParent); + ImmutableFetchList visitFetches(FetchParent fetchParent); - List visitNestedFetches(FetchParent fetchParent); + ImmutableFetchList visitNestedFetches(FetchParent fetchParent); boolean isResolvingCircularFetch(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultGraphPrinter.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultGraphPrinter.java index 6129b5563e..beaa4873bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultGraphPrinter.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/DomainResultGraphPrinter.java @@ -6,6 +6,7 @@ */ package org.hibernate.sql.results.graph; +import java.util.Iterator; import java.util.List; import org.hibernate.internal.log.SubSystemLogging; @@ -114,12 +115,9 @@ public class DomainResultGraphPrinter { // visitKeyGraphNode( identifierFetch, lastInBranch ); // } - final int numberOfFetches = fetchParent.getFetches().size(); - - for ( int i = 0; i < numberOfFetches; i++ ) { - final Fetch fetch = fetchParent.getFetches().get( i ); - - final boolean lastInBranch = i + 1 == numberOfFetches; + for ( Iterator iterator = fetchParent.getFetches().iterator(); iterator.hasNext(); ) { + final Fetch fetch = iterator.next(); + final boolean lastInBranch = !iterator.hasNext(); visitGraphNode( fetch, lastInBranch ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchList.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchList.java new file mode 100644 index 0000000000..28f8f9ca1f --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchList.java @@ -0,0 +1,83 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.graph; + +import java.util.function.Consumer; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; + +import org.hibernate.Incubating; +import org.hibernate.engine.FetchTiming; +import org.hibernate.mapping.IndexedConsumer; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.sql.results.graph.basic.BasicFetch; +import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch; +import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; + +/** + * This is essentially a List of Fetch(es), but exposing + * an interface which is more suitable to our needs; in particular + * it expresses the immutable nature of this structure, and allows + * us to extend it with additional convenience methods such as + * {@link #indexedForEach(IndexedConsumer)}. + * And additional reason for the custom interface is to allow + * custom implementations which can be highly optimised as + * necessary for our specific needs; for example the + * implementation {@link org.hibernate.sql.results.graph.internal.ImmutableFetchList} + * is able to avoid caching problems related to JDK-8180450, which would + * not have been possible with a standard generic container. + * @since 6.2 + */ +@Incubating +public interface FetchList extends Iterable { + + int size(); + + boolean isEmpty(); + + Fetch get(Fetchable fetchable); + + void forEach(Consumer consumer); + + void indexedForEach(IndexedConsumer consumer); + + default Stream stream() { + return StreamSupport.stream( spliterator(), false ); + } + + default boolean hasJoinFetches() { + for ( Fetch fetch : this ) { + if ( fetch instanceof BasicFetch || fetch.getTiming() == FetchTiming.DELAYED ) { + // That's fine + } + else if ( fetch instanceof EmbeddableResultGraphNode ) { + // Check all these fetches as well + if ( ( (EmbeddableResultGraphNode) fetch ).hasJoinFetches() ) { + return true; + } + } + else { + return true; + } + } + return false; + } + + default boolean containsCollectionFetches() { + for ( Fetch fetch : this ) { + if ( fetch instanceof EagerCollectionFetch ) { + return true; + } + else if ( fetch instanceof FetchParent && ( (FetchParent) fetch ).containsCollectionFetches() ) { + return true; + } + } + return false; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchParent.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchParent.java index 165291fd0d..7947c2d9fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchParent.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchParent.java @@ -6,8 +6,6 @@ */ package org.hibernate.sql.results.graph; -import java.util.List; - import org.hibernate.Incubating; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.EmbeddableMappingType; @@ -17,6 +15,7 @@ import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.spi.EntityIdentifierNavigablePath; import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; /** * Contract for things that can be the parent of a fetch @@ -84,10 +83,14 @@ public interface FetchParent extends DomainResultGraphNode { /** * Retrieve the fetches owned by this fetch source. */ - List getFetches(); + ImmutableFetchList getFetches(); Fetch findFetch(Fetchable fetchable); + boolean hasJoinFetches(); + + boolean containsCollectionFetches(); + default FetchParent getRoot() { if ( this instanceof Fetch ) { return ( (Fetch) this ).getFetchParent().getRoot(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/Fetchable.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/Fetchable.java index 1f13f877c5..836d68eeba 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/Fetchable.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/Fetchable.java @@ -8,7 +8,9 @@ package org.hibernate.sql.results.graph; import org.hibernate.Incubating; import org.hibernate.engine.FetchTiming; +import org.hibernate.mapping.IndexedConsumer; import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.spi.NavigablePath; @@ -24,6 +26,16 @@ public interface Fetchable extends ModelPart { */ String getFetchableName(); + /** + * The key that identifies this {@linkplain Fetchable} within a {@link FetchableContainer}. + * If this {@linkplain Fetchable} is part of {@link FetchableContainer#visitFetchables(IndexedConsumer, EntityMappingType)}, + * the values is guaranteed to be between 0 (inclusive) and {@link FetchableContainer#getNumberOfFetchableKeys()} (exclusive). + * Other {@linkplain Fetchable} objects may have a special negative value. + *

+ * The main intent of this key is to index e.g. {@link Fetch} objects in an array. + */ + int getFetchableKey(); + /** * The configured fetch timing and style */ diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchableContainer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchableContainer.java index ce584c75f5..018ea6a440 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchableContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/FetchableContainer.java @@ -34,6 +34,13 @@ public interface FetchableContainer extends ModelPartContainer { */ int getNumberOfFetchables(); + /** + * The number of fetchables in the container + */ + default int getNumberOfFetchableKeys() { + return getNumberOfFetchables(); + } + default Fetchable getKeyFetchable(int position) { List fetchables = new ArrayList<>( getNumberOfKeyFetchables() ); visitKeyFetchables( fetchable -> fetchables.add( fetchable ), null ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/CollectionDomainResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/CollectionDomainResult.java index eb375e05e8..bbf1705d3e 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/CollectionDomainResult.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/CollectionDomainResult.java @@ -26,6 +26,7 @@ import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.collection.CollectionInitializer; import org.hibernate.sql.results.graph.collection.CollectionResultGraphNode; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.type.descriptor.java.JavaType; /** @@ -127,8 +128,8 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra } @Override - public List getFetches() { - return Collections.emptyList(); + public ImmutableFetchList getFetches() { + return ImmutableFetchList.EMPTY; } @Override @@ -136,4 +137,14 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra return null; } + @Override + public boolean hasJoinFetches() { + return false; + } + + @Override + public boolean containsCollectionFetches() { + return false; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EagerCollectionFetch.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EagerCollectionFetch.java index 4dafb49d79..577165e9c5 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EagerCollectionFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/EagerCollectionFetch.java @@ -23,11 +23,13 @@ import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.FetchList; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.sql.results.graph.collection.CollectionInitializer; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.type.descriptor.java.JavaType; /** @@ -40,7 +42,7 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent private final Fetch elementFetch; private final Fetch indexFetch; - private final List fetches; + private final ImmutableFetchList fetches; private final CollectionInitializerProducer initializerProducer; @@ -104,17 +106,17 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent creationState ); - fetches = Collections.unmodifiableList( creationState.visitFetches( this ) ); + fetches = creationState.visitFetches( this ); if ( fetchedAttribute.getIndexDescriptor() != null ) { assert fetches.size() == 2; - indexFetch = fetches.get( 0 ); - elementFetch = fetches.get( 1 ); + indexFetch = fetches.get( fetchedAttribute.getIndexDescriptor() ); + elementFetch = fetches.get( fetchedAttribute.getElementDescriptor() ); } else { if ( !fetches.isEmpty() ) { // might be empty due to fetch depth limit assert fetches.size() == 1; indexFetch = null; - elementFetch = fetches.get( 0 ); + elementFetch = fetches.get( fetchedAttribute.getElementDescriptor() ); } else { indexFetch = null; @@ -180,7 +182,7 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent } @Override - public List getFetches() { + public ImmutableFetchList getFetches() { return fetches; } @@ -200,6 +202,18 @@ public class EagerCollectionFetch extends CollectionFetch implements FetchParent } } + @Override + public boolean hasJoinFetches() { + // This is already a fetch, so this line should actually never be hit + return true; + } + + @Override + public boolean containsCollectionFetches() { + // This is already a collection fetch, so this line should actually never be hit + return true; + } + @Override public JavaType getResultJavaType() { return getFetchedMapping().getJavaType(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AggregateEmbeddableResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AggregateEmbeddableResultImpl.java index 0a99e7af09..8de0be13cb 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AggregateEmbeddableResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AggregateEmbeddableResultImpl.java @@ -32,6 +32,7 @@ import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; import org.hibernate.type.spi.TypeConfiguration; @@ -106,9 +107,9 @@ public class AggregateEmbeddableResultImpl extends AbstractFetchParent implem this.containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() ); } - private static boolean determineIfContainedAnyScalars(List fetches) { - for ( int i = 0; i < fetches.size(); i++ ) { - if ( fetches.get( i ).containsAnyNonScalarResults() ) { + private static boolean determineIfContainedAnyScalars(ImmutableFetchList fetches) { + for ( Fetch fetch : fetches ) { + if ( fetch.containsAnyNonScalarResults() ) { return true; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableExpressionResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableExpressionResultImpl.java index 98b0c9b350..54b20fa388 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableExpressionResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableExpressionResultImpl.java @@ -6,23 +6,15 @@ */ package org.hibernate.sql.results.graph.embeddable.internal; -import java.util.ArrayList; -import java.util.List; - import org.hibernate.engine.FetchTiming; -import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.internal.BasicAttributeMapping; import org.hibernate.spi.NavigablePath; -import org.hibernate.sql.ast.SqlAstJoinType; -import org.hibernate.sql.ast.spi.FromClauseAccess; import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlExpressionResolver; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.expression.SqlTuple; -import org.hibernate.sql.ast.tree.from.TableGroup; -import org.hibernate.sql.ast.tree.from.TableGroupJoin; import org.hibernate.sql.results.graph.AbstractFetchParent; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; @@ -34,6 +26,7 @@ import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.spi.TypeConfiguration; @@ -53,7 +46,7 @@ public class EmbeddableExpressionResultImpl extends AbstractFetchParent imple super( modelPart.getEmbeddableTypeDescriptor(), navigablePath ); this.resultVariable = resultVariable; - final List fetches = new ArrayList<>(); + final ImmutableFetchList.Builder fetches = new ImmutableFetchList.Builder( modelPart ); final EmbeddableMappingType mappingType = modelPart.getEmbeddableTypeDescriptor(); final int numberOfAttributeMappings = mappingType.getNumberOfAttributeMappings(); final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState(); @@ -81,13 +74,13 @@ public class EmbeddableExpressionResultImpl extends AbstractFetchParent imple ); } - this.containsAnyNonScalars = determineIfContainedAnyScalars( fetches ); - resetFetches( fetches ); + resetFetches( fetches.build() ); + this.containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() ); } - private static boolean determineIfContainedAnyScalars(List fetches) { - for ( int i = 0; i < fetches.size(); i++ ) { - if ( fetches.get( i ).containsAnyNonScalarResults() ) { + private static boolean determineIfContainedAnyScalars(ImmutableFetchList fetches) { + for ( Fetch fetch : fetches ) { + if ( fetch.containsAnyNonScalarResults() ) { return true; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableResultImpl.java index a9ddf1c867..abe9c4f558 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableResultImpl.java @@ -25,6 +25,7 @@ import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; import org.hibernate.sql.results.graph.embeddable.EmbeddableResult; import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.type.descriptor.java.JavaType; /** @@ -76,9 +77,9 @@ public class EmbeddableResultImpl extends AbstractFetchParent implements Embe containsAnyNonScalars = determineIfContainedAnyScalars( getFetches() ); } - private static boolean determineIfContainedAnyScalars(List fetches) { - for ( int i = 0; i < fetches.size(); i++ ) { - if ( fetches.get( i ).containsAnyNonScalarResults() ) { + private static boolean determineIfContainedAnyScalars(ImmutableFetchList fetches) { + for ( Fetch fetch : fetches ) { + if ( fetch.containsAnyNonScalarResults() ) { return true; } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java index 5679d40364..0df8820922 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java @@ -53,37 +53,20 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent final NavigablePath navigablePath = getNavigablePath(); final TableGroup entityTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess() .getTableGroup( navigablePath ); - final EntityIdentifierNavigablePath identifierNavigablePath = new EntityIdentifierNavigablePath( navigablePath, attributeName( identifierMapping ) ); if ( navigablePath.getParent() == null && !creationState.forceIdentifierSelection() ) { identifierFetch = null; - visitIdentifierMapping( identifierNavigablePath, creationState, identifierMapping, entityTableGroup ); + visitIdentifierMapping( + new EntityIdentifierNavigablePath( navigablePath, attributeName( identifierMapping ) ), + creationState, + identifierMapping, + entityTableGroup + ); } else { - identifierFetch = ( (Fetchable) identifierMapping ).generateFetch( - fetchParent, - identifierNavigablePath, - FetchTiming.IMMEDIATE, - true, - null, - creationState - ); + identifierFetch = creationState.visitIdentifierFetch( this ); } - final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); - // No need to fetch the discriminator if this type does not have subclasses - if ( discriminatorMapping != null && entityDescriptor.hasSubclasses() ) { - discriminatorFetch = discriminatorMapping.generateFetch( - fetchParent, - navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ), - FetchTiming.IMMEDIATE, - true, - null, - creationState - ); - } - else { - discriminatorFetch = null; - } + discriminatorFetch = creationState.visitDiscriminatorFetch( this ); final EntityRowIdMapping rowIdMapping = entityDescriptor.getRowIdMapping(); if ( rowIdMapping == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/AbstractNonJoinedEntityFetch.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/AbstractNonJoinedEntityFetch.java index 94a7fbcf6a..38a1eeb3f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/AbstractNonJoinedEntityFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/AbstractNonJoinedEntityFetch.java @@ -16,6 +16,7 @@ import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.entity.EntityFetch; import org.hibernate.sql.results.graph.entity.EntityValuedFetchable; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; /** * @author Steve Ebersole @@ -55,8 +56,8 @@ public abstract class AbstractNonJoinedEntityFetch implements EntityFetch { } @Override - public List getFetches() { - return Collections.emptyList(); + public ImmutableFetchList getFetches() { + return ImmutableFetchList.EMPTY; } @Override @@ -64,6 +65,16 @@ public abstract class AbstractNonJoinedEntityFetch implements EntityFetch { return null; } + @Override + public boolean hasJoinFetches() { + return false; + } + + @Override + public boolean containsCollectionFetches() { + return false; + } + @Override public EntityMappingType getReferencedMappingType() { return fetchedModelPart.getEntityMappingType(); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/internal/ImmutableFetchList.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/internal/ImmutableFetchList.java new file mode 100644 index 0000000000..b63f547ec5 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/internal/ImmutableFetchList.java @@ -0,0 +1,141 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.sql.results.graph.internal; + +import java.util.Collections; +import java.util.Iterator; +import java.util.function.Consumer; + +import org.hibernate.mapping.IndexedConsumer; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.persister.internal.ImmutableAttributeMappingList; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.FetchList; +import org.hibernate.sql.results.graph.Fetchable; +import org.hibernate.sql.results.graph.FetchableContainer; + +public final class ImmutableFetchList implements FetchList { + + public static ImmutableFetchList EMPTY = new ImmutableFetchList(); + private final Fetch[] fetches; + + private ImmutableFetchList() { + this.fetches = null; + } + + private ImmutableFetchList(Fetch[] fetches) { + assert fetches != null; + this.fetches = fetches; + } + + @Override + public int size() { + if ( fetches == null ) { + return 0; + } + int size = 0; + for ( Fetch fetch : fetches ) { + if ( fetch != null ) { + size++; + } + } + return size; + } + + @Override + public boolean isEmpty() { + return fetches == null; + } + + @Override + public Fetch get(Fetchable fetchable) { + return fetches == null ? null : fetches[fetchable.getFetchableKey()]; + } + + @Override + public void forEach(Consumer consumer) { + if ( fetches != null ) { + for ( Fetch fetch : fetches ) { + if ( fetch != null ) { + consumer.accept( fetch ); + } + } + } + } + + @Override + public void indexedForEach(IndexedConsumer consumer) { + if ( fetches != null ) { + int index = 0; + for ( Fetch fetch : fetches ) { + if ( fetch != null ) { + consumer.accept( index++, fetch ); + } + } + } + } + + @Override + public Iterator iterator() { + if ( fetches == null ) { + return Collections.emptyIterator(); + } + return new FetchIterator(); + } + + private final class FetchIterator implements Iterator { + + private int idx; + + public FetchIterator() { + assert ImmutableFetchList.this.fetches != null; + this.idx = 0; + while (ImmutableFetchList.this.fetches[idx] == null) { + idx++; + } + } + + @Override + public boolean hasNext() { + return idx < ImmutableFetchList.this.fetches.length; + } + + @Override + public Fetch next() { + final Fetch fetch = ImmutableFetchList.this.fetches[idx++]; + while ( idx < ImmutableFetchList.this.fetches.length ) { + if ( ImmutableFetchList.this.fetches[idx] != null ) { + break; + } + idx++; + } + return fetch; + } + + } + + public static class Builder { + private final Fetch[] fetches; + + public Builder(FetchableContainer container) { + this.fetches = new Fetch[container.getNumberOfFetchableKeys()]; + } + + public void add(Fetch fetch) { + fetches[fetch.getFetchedMapping().getFetchableKey()] = fetch; + } + + public ImmutableFetchList build() { + for ( Fetch fetch : fetches ) { + if ( fetch != null ) { + return new ImmutableFetchList( fetches ); + } + } + return EMPTY; + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/ScrollableResultsConsumer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/ScrollableResultsConsumer.java index eb2f1090d4..8c2bd15888 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/spi/ScrollableResultsConsumer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/spi/ScrollableResultsConsumer.java @@ -12,8 +12,6 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.FetchingScrollableResultsImpl; import org.hibernate.internal.ScrollableResultsImpl; import org.hibernate.sql.results.graph.DomainResult; -import org.hibernate.sql.results.graph.Fetch; -import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMapping; import org.hibernate.sql.results.jdbc.spi.JdbcValues; @@ -74,15 +72,9 @@ public class ScrollableResultsConsumer implements ResultsConsumer> domainResults = valuesMapping.getDomainResults(); - for ( DomainResult domainResult : domainResults ) { - if ( domainResult instanceof EntityResult ) { - EntityResult entityResult = (EntityResult) domainResult; - final List fetches = entityResult.getFetches(); - for ( Fetch fetch : fetches ) { - if ( fetch instanceof EagerCollectionFetch ) { - return true; - } - } + for ( DomainResult domainResult : domainResults ) { + if ( domainResult instanceof EntityResult && ( (EntityResult) domainResult ).containsCollectionFetches() ) { + return true; } } return false; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/CriteriaEntityGraphTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/CriteriaEntityGraphTest.java index 07816041ae..f7844835e6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/CriteriaEntityGraphTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/CriteriaEntityGraphTest.java @@ -54,6 +54,7 @@ import org.hibernate.sql.results.graph.entity.EntityFetch; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl; import org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.orm.junit.DomainModel; @@ -190,13 +191,12 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware { Fetchable fetchable = getFetchable( "company", Person.class ); final Fetch companyFetch = ownerEntityResult.findFetch( fetchable ); - List fetches = ownerEntityResult.getFetches(); assertThat( companyFetch, notNullValue() ); final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult(); - assertThat( companyEntityResult.getFetches(), hasSize( 1 ) ); + assertThat( companyEntityResult.getFetches().size(), is( 1 ) ); - final Fetch shipAddressesFetch = companyEntityResult.getFetches().get( 0 ); + final Fetch shipAddressesFetch = companyEntityResult.getFetches().iterator().next(); assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) ); assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) ); } ); @@ -348,9 +348,9 @@ public class CriteriaEntityGraphTest implements SessionFactoryScopeAware { final EntityResult entityResult = (EntityResult) domainResult; assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) ); - assertThat( entityResult.getFetches(), hasSize( 1 ) ); + assertThat( entityResult.getFetches().size(), is( 1 ) ); - final Fetch fetch = entityResult.getFetches().get( 0 ); + final Fetch fetch = entityResult.getFetches().iterator().next(); assertThat( fetch, instanceOf( EntityFetch.class ) ); final EntityFetch entityFetch = (EntityFetch) fetch; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/EntityGraphLoadPlanBuilderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/EntityGraphLoadPlanBuilderTest.java index c3d27d70e7..b471680d05 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/EntityGraphLoadPlanBuilderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/EntityGraphLoadPlanBuilderTest.java @@ -189,9 +189,9 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware assertThat( companyFetch, notNullValue() ); final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult(); - assertThat( companyEntityResult.getFetches(), hasSize( 1 ) ); + assertThat( companyEntityResult.getFetches().size(), is( 1 ) ); - final Fetch shipAddressesFetch = companyEntityResult.getFetches().get( 0 ); + final Fetch shipAddressesFetch = companyEntityResult.getFetches().iterator().next(); assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) ); assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) ); } ); @@ -337,9 +337,9 @@ public class EntityGraphLoadPlanBuilderTest implements SessionFactoryScopeAware final EntityResult entityResult = (EntityResult) domainResult; assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) ); - assertThat( entityResult.getFetches(), hasSize( 1 ) ); + assertThat( entityResult.getFetches().size(), is( 1 ) ); - final Fetch fetch = entityResult.getFetches().get( 0 ); + final Fetch fetch = entityResult.getFetches().iterator().next(); assertThat( fetch, instanceOf( EntityFetch.class ) ); final EntityFetch entityFetch = (EntityFetch) fetch; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/HqlEntityGraphTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/HqlEntityGraphTest.java index 7cdc809881..199922b277 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/HqlEntityGraphTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/HqlEntityGraphTest.java @@ -191,9 +191,9 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware { assertThat( companyFetch, notNullValue() ); final EntityResult companyEntityResult = ( (EntityFetchJoinedImpl) companyFetch).getEntityResult(); - assertThat( companyEntityResult.getFetches(), hasSize( 1 ) ); + assertThat( companyEntityResult.getFetches().size(), is( 1 ) ); - final Fetch shipAddressesFetch = companyEntityResult.getFetches().get( 0 ); + final Fetch shipAddressesFetch = companyEntityResult.getFetches().iterator().next(); assertThat( shipAddressesFetch.getFetchedMapping().getPartName(), is( "shipAddresses" ) ); assertThat( shipAddressesFetch, instanceOf( DelayedCollectionFetch.class ) ); } ); @@ -345,9 +345,9 @@ public class HqlEntityGraphTest implements SessionFactoryScopeAware { final EntityResult entityResult = (EntityResult) domainResult; assertThat( entityResult.getReferencedModePart().getJavaType().getJavaTypeClass(), assignableTo( expectedEntityJpaClass ) ); - assertThat( entityResult.getFetches(), hasSize( 1 ) ); + assertThat( entityResult.getFetches().size(), is( 1 ) ); - final Fetch fetch = entityResult.getFetches().get( 0 ); + final Fetch fetch = entityResult.getFetches().iterator().next(); assertThat( fetch, instanceOf( EntityFetch.class ) ); final EntityFetch entityFetch = (EntityFetch) fetch; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/LoadPlanBuilderTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/LoadPlanBuilderTest.java index f67f2e4b85..3eb8780e15 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/LoadPlanBuilderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entitygraph/ast/LoadPlanBuilderTest.java @@ -73,12 +73,12 @@ public class LoadPlanBuilderTest { final EntityResult entityResult = (EntityResult) domainResult; assertThat( entityResult.getFetches() ).hasSize( 2 ); - final Fetch txtFetch = entityResult.getFetches().get( 0 ); + final Fetch txtFetch = entityResult.getFetches().get( entityDescriptor.findAttributeMapping( "msgTxt" ) ); assertThat( txtFetch ).isNotNull(); assertThat( txtFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "msgTxt" ); assertThat( txtFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE ); - final Fetch posterFetch = entityResult.getFetches().get( 1 ); + final Fetch posterFetch = entityResult.getFetches().get( entityDescriptor.findAttributeMapping( "poster" ) ); assertThat( posterFetch ).isNotNull(); assertThat( posterFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "poster" ); assertThat( posterFetch.getTiming() ).isEqualTo( FetchTiming.DELAYED ); @@ -114,12 +114,12 @@ public class LoadPlanBuilderTest { final EntityResult entityResult = (EntityResult) domainResult; assertThat( entityResult.getFetches() ).hasSize( 2 ); - final Fetch txtFetch = entityResult.getFetches().get( 0 ); + final Fetch txtFetch = entityResult.getFetches().get( entityDescriptor.findAttributeMapping( "msgTxt" ) ); assertThat( txtFetch ).isNotNull(); assertThat( txtFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "msgTxt" ); assertThat( txtFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE ); - final Fetch posterFetch = entityResult.getFetches().get( 1 ); + final Fetch posterFetch = entityResult.getFetches().get( entityDescriptor.findAttributeMapping( "poster" ) ); assertThat( posterFetch ).isNotNull(); assertThat( posterFetch.getFetchedMapping().getFetchableName() ).isEqualTo( "poster" ); assertThat( posterFetch.getTiming() ).isEqualTo( FetchTiming.IMMEDIATE ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/MappedFetchTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/MappedFetchTests.java index 4d196cbb0b..c96e87eac2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/loading/MappedFetchTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/loading/MappedFetchTests.java @@ -36,6 +36,7 @@ import org.hibernate.sql.results.graph.collection.internal.EagerCollectionFetch; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.internal.ImmutableFetchList; import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.SessionFactory; @@ -85,22 +86,22 @@ public class MappedFetchTests { assertThat( domainResult, instanceOf( EntityResult.class ) ); final EntityResult entityResult = (EntityResult) domainResult; - final List fetches = entityResult.getFetches(); + final ImmutableFetchList fetches = entityResult.getFetches(); // name + both lists assertThat( fetches.size(), is( 3 ) ); // order is alphabetical... - final Fetch nameFetch = fetches.get( 0 ); + final Fetch nameFetch = fetches.get( rootEntityDescriptor.findAttributeMapping( "name" ) ); assertThat( nameFetch.getFetchedMapping().getFetchableName(), is( "name" ) ); assertThat( nameFetch, instanceOf( BasicFetch.class ) ); - final Fetch nickNamesFetch = fetches.get( 1 ); + final Fetch nickNamesFetch = fetches.get( rootEntityDescriptor.findAttributeMapping( "nickNames" ) ); assertThat( nickNamesFetch.getFetchedMapping().getFetchableName(), is( "nickNames" ) ); assertThat( nickNamesFetch, instanceOf( EagerCollectionFetch.class ) ); - final Fetch simpleEntitiesFetch = fetches.get( 2 ); + final Fetch simpleEntitiesFetch = fetches.get( rootEntityDescriptor.findAttributeMapping( "simpleEntities" ) ); assertThat( simpleEntitiesFetch.getFetchedMapping().getFetchableName(), is( "simpleEntities" ) ); assertThat( simpleEntitiesFetch, instanceOf( DelayedCollectionFetch.class ) );