From 3ee817008a702132c85b8221408b985c35e6577c Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 11 Apr 2023 13:33:26 +0200 Subject: [PATCH] HHH-16468 Don't create fetch for _identifierMapper anymore --- .../ast/internal/LoaderSelectBuilder.java | 2 +- .../NonAggregatedIdentifierMappingImpl.java | 40 +++ .../DomainResultCreationStateImpl.java | 2 +- .../sqm/sql/BaseSqmToSqlAstConverter.java | 2 +- .../AbstractEmbeddableInitializer.java | 236 +++++--------- ...ggregatedIdentifierMappingInitializer.java | 289 ++++++++++++++++++ .../EmbeddableForeignKeyResultImpl.java | 5 +- .../internal/NestedRowProcessingState.java | 39 +++ .../NonAggregatedIdentifierMappingFetch.java | 41 +++ ...atedIdentifierMappingFetchInitializer.java | 31 ++ .../NonAggregatedIdentifierMappingResult.java | 45 +++ ...tedIdentifierMappingResultInitializer.java | 33 ++ .../entity/AbstractEntityInitializer.java | 8 + .../RowProcessingStateStandardImpl.java | 33 ++ 14 files changed, 642 insertions(+), 164 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AbstractNonAggregatedIdentifierMappingInitializer.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingFetch.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingFetchInitializer.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingResult.java create mode 100644 hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingResultInitializer.java 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 b1d16b9c00..cb4e2fc23f 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 @@ -689,7 +689,7 @@ private BiConsumer createFetchableBiConsumer( LoaderSqlAstCreationState creationState, ImmutableFetchList.Builder fetches) { return (fetchable, isKeyFetchable) -> { - if ( !fetchable.isSelectable() ) { + if ( !fetchable.isSelectable() || fetchable.getPartName().equals( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ) ) { return; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java index 8ff98019bb..a25d4af054 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/NonAggregatedIdentifierMappingImpl.java @@ -10,6 +10,7 @@ import java.util.function.BiConsumer; import org.hibernate.cache.MutableCacheKeyBuilder; +import org.hibernate.engine.FetchTiming; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -35,8 +36,15 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; +import org.hibernate.sql.results.graph.DomainResult; 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.internal.EmbeddableFetchImpl; +import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableResultImpl; +import org.hibernate.sql.results.graph.embeddable.internal.NonAggregatedIdentifierMappingFetch; +import org.hibernate.sql.results.graph.embeddable.internal.NonAggregatedIdentifierMappingResult; /** * A "non-aggregated" composite identifier. @@ -316,6 +324,38 @@ public void applySqlSelections( identifierValueMapper.applySqlSelections( navigablePath, tableGroup, creationState, selectionConsumer ); } + @Override + public DomainResult createDomainResult( + NavigablePath navigablePath, + TableGroup tableGroup, + String resultVariable, + DomainResultCreationState creationState) { + return new NonAggregatedIdentifierMappingResult<>( + navigablePath, + this, + resultVariable, + creationState + ); + } + + @Override + public Fetch generateFetch( + FetchParent fetchParent, + NavigablePath fetchablePath, + FetchTiming fetchTiming, + boolean selected, + String resultVariable, + DomainResultCreationState creationState) { + return new NonAggregatedIdentifierMappingFetch( + fetchablePath, + this, + fetchParent, + fetchTiming, + selected, + creationState + ); + } + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // EmbeddableValuedFetchable 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 385457a46f..affa93b51c 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 @@ -459,7 +459,7 @@ public ImmutableFetchList visitFetches(FetchParent fetchParent) { private Consumer createFetchableConsumer(FetchParent fetchParent, ImmutableFetchList.Builder fetches) { return fetchable -> { - if ( !fetchable.isSelectable() ) { + if ( !fetchable.isSelectable() || fetchable.getPartName().equals( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ) ) { return; } final String fetchableName = fetchable.getFetchableName(); 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 aac15f504a..f912c9d645 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 @@ -7144,7 +7144,7 @@ public Fetch visitIdentifierFetch(EntityResultGraphNode fetchParent) { } private Fetch createFetch(FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) { - if ( !fetchable.isSelectable() ) { + if ( !fetchable.isSelectable() || fetchable.getPartName().equals( NavigablePath.IDENTIFIER_MAPPER_PROPERTY ) ) { return null; } final NavigablePath resolvedNavigablePath = fetchParent.resolveNavigablePath( fetchable ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java index 9c1782a094..0b0f4d0af0 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/AbstractEmbeddableInitializer.java @@ -9,17 +9,12 @@ import java.util.List; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.metamodel.internal.StandardEmbeddableInstantiator; -import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.VirtualModelPart; -import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; -import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.ValueAccess; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.proxy.HibernateProxy; @@ -37,41 +32,27 @@ import org.hibernate.sql.results.internal.NullValueAssembler; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; -import static java.lang.Boolean.FALSE; -import static java.lang.Boolean.TRUE; import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; import static org.hibernate.sql.results.graph.entity.internal.BatchEntityInsideEmbeddableSelectFetchInitializer.BATCH_PROPERTY; /** * @author Steve Ebersole */ -public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentAccess implements EmbeddableInitializer, - ValueAccess { - private static final Object NULL_MARKER = new Object() { - @Override - public String toString() { - return "Composite NULL_MARKER"; - } - }; +public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentAccess + implements EmbeddableInitializer, ValueAccess { private final NavigablePath navigablePath; private final EmbeddableValuedModelPart embedded; - private final EmbeddableMappingType representationEmbeddable; - private final EmbeddableRepresentationStrategy representationStrategy; private final FetchParentAccess fetchParentAccess; private final boolean createEmptyCompositesEnabled; private final SessionFactoryImplementor sessionFactory; private final List> assemblers; - private final boolean usesStandardInstantiation; - // per-row state private final Object[] rowState; - private Boolean stateAllNull; - private Boolean stateInjected; + private State state = State.INITIAL; protected Object compositeInstance; - private boolean isParentInitialized; private RowProcessingState wrappedProcessingState; public AbstractEmbeddableInitializer( @@ -83,16 +64,6 @@ public AbstractEmbeddableInitializer( this.fetchParentAccess = fetchParentAccess; final EmbeddableMappingType embeddableTypeDescriptor = embedded.getEmbeddableTypeDescriptor(); - if ( embedded instanceof CompositeIdentifierMapping ) { - representationEmbeddable = ( (CompositeIdentifierMapping) embedded ).getMappedIdEmbeddableTypeDescriptor(); - } - else { - representationEmbeddable = embeddableTypeDescriptor; - } - - this.representationStrategy = representationEmbeddable.getRepresentationStrategy(); - this.usesStandardInstantiation = representationStrategy.getInstantiator() instanceof StandardEmbeddableInstantiator; - final int size = embeddableTypeDescriptor.getNumberOfFetchables(); this.rowState = new Object[ size ]; this.assemblers = arrayList( size ); @@ -140,7 +111,7 @@ public NavigablePath getNavigablePath() { @Override public Object getCompositeInstance() { - return compositeInstance == NULL_MARKER ? null : compositeInstance; + return state == State.NULL ? null : compositeInstance; } @Override @@ -174,16 +145,6 @@ public void resolveInstance(RowProcessingState processingState) { public void initializeInstance(RowProcessingState processingState) { EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( "Initializing composite instance [%s]", navigablePath ); - if ( compositeInstance == NULL_MARKER ) { - // we already know it is null - return; - } - - if ( isParentInstanceNull() ) { - compositeInstance = NULL_MARKER; - return; - } - // IMPORTANT: This method might be called multiple times for the same role for a single row. // EmbeddableAssembler calls it as part of its `#assemble` and the RowReader calls it // as part of its normal Initializer handling @@ -203,74 +164,66 @@ public void initializeInstance(RowProcessingState processingState) { // critical in the case we have custom constructor injection. Luckily, custom instantiation // is only allowed for non-key usage atm, so we leverage that distinction here - if ( !usesStandardInstantiation ) { - // we have a custom instantiator - if ( compositeInstance != null ) { + switch ( state ) { + case NULL: return; - } - } - if ( isParentInitialized ) { - return; - } + case INITIAL: + if ( isParentInstanceNull() ) { + state = State.NULL; + return; + } - // We need to possibly wrap the processing state if the embeddable is within an aggregate - if ( wrappedProcessingState == null ) { - wrappedProcessingState = wrapProcessingState( processingState ); - } - initializeInstance( ); - } + // We need to possibly wrap the processing state if the embeddable is within an aggregate + if ( wrappedProcessingState == null ) { + wrappedProcessingState = wrapProcessingState( processingState ); + } + extractRowState( wrappedProcessingState ); + prepareCompositeInstance( wrappedProcessingState ); + if ( state == State.NULL ) { + return; + } + notifyResolutionListeners( compositeInstance ); + case EXTRACTED: + if ( embedded.getParentInjectionAttributePropertyAccess() != null || embedded instanceof VirtualModelPart ) { + handleParentInjection( wrappedProcessingState ); - private void initializeInstance() { - stateInjected = false; - extractRowState( wrappedProcessingState ); - prepareCompositeInstance( wrappedProcessingState ); - if ( isParentInitialized ) { - return; - } - if ( !stateInjected ) { - handleParentInjection( wrappedProcessingState ); - } - - if ( compositeInstance != NULL_MARKER ) { - notifyResolutionListeners( compositeInstance ); - - final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( compositeInstance ); - // If the composite instance has a lazy initializer attached, this means that the embeddable is actually virtual - // and the compositeInstance == entity, so we have to inject the row state into the entity when it finishes resolution - if ( lazyInitializer != null ) { - final Initializer parentInitializer = wrappedProcessingState.resolveInitializer( navigablePath.getParent() ); - if ( parentInitializer != this ) { - ( (FetchParentAccess) parentInitializer ).registerResolutionListener( (entity) -> { - representationEmbeddable.setValues( entity, rowState ); - stateInjected = true; - } ); + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( compositeInstance ); + // If the composite instance has a lazy initializer attached, this means that the embeddable is actually virtual + // and the compositeInstance == entity, so we have to inject the row state into the entity when it finishes resolution + if ( lazyInitializer != null ) { + final Initializer parentInitializer = wrappedProcessingState.resolveInitializer( navigablePath.getParent() ); + if ( parentInitializer != this ) { + ( (FetchParentAccess) parentInitializer ).registerResolutionListener( (entity) -> { + embedded.getEmbeddableTypeDescriptor().setValues( entity, rowState ); + state = State.INJECTED; + } ); + } + else { + // At this point, createEmptyCompositesEnabled is always true, so we generate + // the composite instance. + // + // NOTE: `valuesAccess` is set to null to indicate that all values are null, + // as opposed to returning the all-null value array. the instantiator + // interprets that as the values are not known or were all null. + final Object target = embedded.getEmbeddableTypeDescriptor().getRepresentationStrategy() + .getInstantiator() + .instantiate( this, sessionFactory); + state = State.INJECTED; + lazyInitializer.setImplementation( target ); + } + } + else { + embedded.getEmbeddableTypeDescriptor().setValues( compositeInstance, rowState ); + state = State.INJECTED; + } } else { - // At this point, createEmptyCompositesEnabled is always true, so we generate - // the composite instance. - // - // NOTE: `valuesAccess` is set to null to indicate that all values are null, - // as opposed to returning the all-null value array. the instantiator - // interprets that as the values are not known or were all null. - final Object target = representationStrategy - .getInstantiator() - .instantiate( this, sessionFactory); - stateInjected = true; - lazyInitializer.setImplementation( target ); + state = State.INJECTED; } - } - else if ( stateAllNull == FALSE && stateInjected != TRUE ) { - representationEmbeddable.setValues( compositeInstance, rowState ); - stateInjected = true; - } } } private void prepareCompositeInstance(RowProcessingState processingState) { - if ( compositeInstance != null ) { - return; - } - // Virtual model parts use the owning entity as container which the fetch parent access provides. // For an identifier or foreign key this is called during the resolveKey phase of the fetch parent, // so we can't use the fetch parent access in that case. @@ -282,7 +235,6 @@ private void prepareCompositeInstance(RowProcessingState processingState) { compositeInstance = fetchParentAccess.getInitializedInstance(); EntityInitializer entityInitializer = fetchParentAccess.asEntityInitializer(); if ( entityInitializer != null && entityInitializer.isEntityInitialized() ) { - this.isParentInitialized = true; return; } } @@ -290,7 +242,6 @@ private void prepareCompositeInstance(RowProcessingState processingState) { if ( compositeInstance == null ) { compositeInstance = createCompositeInstance( navigablePath, - representationStrategy, sessionFactory ); } @@ -326,7 +277,7 @@ private boolean isParentInstanceNull() { } private void extractRowState(RowProcessingState processingState) { - stateAllNull = true; + boolean stateAllNull = true; final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() ) || ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() ) || EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() ); @@ -353,51 +304,23 @@ else if ( isKey ) { } } - applyMapsId( processingState ); + state = stateAllNull ? State.NULL : State.EXTRACTED; } - private void applyMapsId(RowProcessingState processingState) { - final SharedSessionContractImplementor session = processingState.getSession(); - if ( embedded instanceof CompositeIdentifierMapping ) { - final CompositeIdentifierMapping cid = (CompositeIdentifierMapping) embedded; - final EmbeddableMappingType mappedIdEmbeddable = cid.getMappedIdEmbeddableTypeDescriptor(); - if ( cid.hasContainingClass() ) { - final EmbeddableMappingType virtualIdEmbeddable = embedded.getEmbeddableTypeDescriptor(); - if ( virtualIdEmbeddable == mappedIdEmbeddable ) { - return; - } - - virtualIdEmbeddable.forEachAttributeMapping( - (position, virtualIdAttribute) -> { - final AttributeMapping mappedIdAttribute = mappedIdEmbeddable.getAttributeMapping( position ); - - if ( virtualIdAttribute instanceof ToOneAttributeMapping - && !( mappedIdAttribute instanceof ToOneAttributeMapping ) ) { - final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) virtualIdAttribute; - final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor(); - final Object associationKey = fkDescriptor.getAssociationKeyFromSide( - rowState[position], - toOneAttributeMapping.getSideNature().inverse(), - session - ); - rowState[position] = associationKey; - } - } - ); + private Object createCompositeInstance(NavigablePath navigablePath, SessionFactoryImplementor sessionFactory) { + if ( state == State.NULL ) { + // todo (6.0) : should we initialize the composite instance if it has a parent attribute? +// if ( !createEmptyCompositesEnabled && embedded.getParentInjectionAttributePropertyAccess() == null ) { + if ( !createEmptyCompositesEnabled ) { + return null; } } - } - private Object createCompositeInstance( - NavigablePath navigablePath, - EmbeddableRepresentationStrategy representationStrategy, - SessionFactoryImplementor sessionFactory) { - if ( !createEmptyCompositesEnabled && stateAllNull == TRUE ) { - return NULL_MARKER; - } - - final Object instance = representationStrategy.getInstantiator().instantiate( this, sessionFactory ); - stateInjected = true; + final Object instance = embedded.getEmbeddableTypeDescriptor() + .getRepresentationStrategy() + .getInstantiator() + .instantiate( this, sessionFactory ); + state = State.EXTRACTED; EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( "Created composite instance [%s] : %s", navigablePath, instance ); @@ -406,12 +329,12 @@ private Object createCompositeInstance( @Override public Object[] getValues() { - return stateAllNull ? null : rowState; + return state == State.NULL ? null : rowState; } @Override public T getValue(int i, Class clazz) { - return stateAllNull ? null : clazz.cast( rowState[i] ); + return state == State.NULL ? null : clazz.cast( rowState[i] ); } @Override @@ -420,17 +343,6 @@ public Object getOwner() { } private void handleParentInjection(RowProcessingState processingState) { - // todo (6.0) : should we initialize the composite instance if we get here and it is null (not NULL_MARKER)? - - // we want to avoid injection for `NULL_MARKER` - if ( compositeInstance == null || compositeInstance == NULL_MARKER ) { - EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( - "Skipping parent injection for null embeddable [%s]", - navigablePath - ); - return; - } - final PropertyAccess parentInjectionAccess = embedded.getParentInjectionAttributePropertyAccess(); if ( parentInjectionAccess == null ) { // embeddable defined no parent injection @@ -504,9 +416,7 @@ private Object determineParentInstance(RowProcessingState processingState) { @Override public void finishUpRow(RowProcessingState rowProcessingState) { compositeInstance = null; - stateAllNull = null; - stateInjected = null; - isParentInitialized = false; + state = State.INITIAL; wrappedProcessingState = null; clearResolutionListeners(); @@ -516,4 +426,10 @@ public void finishUpRow(RowProcessingState rowProcessingState) { public String toString() { return getClass().getSimpleName() + "(" + navigablePath + ") : `" + getInitializedPart().getJavaType().getJavaTypeClass() + "`"; } + enum State { + INITIAL, + EXTRACTED, + NULL, + INJECTED + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AbstractNonAggregatedIdentifierMappingInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AbstractNonAggregatedIdentifierMappingInitializer.java new file mode 100644 index 0000000000..b2ad3de5b7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/AbstractNonAggregatedIdentifierMappingInitializer.java @@ -0,0 +1,289 @@ +/* + * 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.embeddable.internal; + +import java.util.List; + +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.EmbeddableMappingType; +import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; +import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; +import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping; +import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; +import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; +import org.hibernate.metamodel.spi.ValueAccess; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.proxy.LazyInitializer; +import org.hibernate.spi.EntityIdentifierNavigablePath; +import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.AbstractFetchParentAccess; +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResultAssembler; +import org.hibernate.sql.results.graph.Fetch; +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.embeddable.EmbeddableInitializer; +import org.hibernate.sql.results.graph.embeddable.EmbeddableLoadingLogger; +import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; +import org.hibernate.sql.results.graph.entity.EntityInitializer; +import org.hibernate.sql.results.internal.NullValueAssembler; +import org.hibernate.sql.results.jdbc.spi.RowProcessingState; + +import static org.hibernate.internal.util.collections.CollectionHelper.arrayList; +import static org.hibernate.sql.results.graph.entity.internal.BatchEntityInsideEmbeddableSelectFetchInitializer.BATCH_PROPERTY; + +/** + * @author Steve Ebersole + */ +public abstract class AbstractNonAggregatedIdentifierMappingInitializer extends AbstractFetchParentAccess + implements EmbeddableInitializer, ValueAccess { + + private final NavigablePath navigablePath; + private final NonAggregatedIdentifierMapping embedded; + private final EmbeddableMappingType representationEmbeddable; + private final EmbeddableRepresentationStrategy representationStrategy; + private final FetchParentAccess fetchParentAccess; + private final SessionFactoryImplementor sessionFactory; + + private final List> assemblers; + private final boolean hasIdClass; + + + // per-row state + private final Object[] virtualIdState; + private final Object[] idClassState; + private State state = State.INITIAL; + protected Object compositeInstance; + + public AbstractNonAggregatedIdentifierMappingInitializer( + EmbeddableResultGraphNode resultDescriptor, + FetchParentAccess fetchParentAccess, + AssemblerCreationState creationState) { + this.navigablePath = resultDescriptor.getNavigablePath(); + this.embedded = (NonAggregatedIdentifierMapping) resultDescriptor.getReferencedMappingContainer(); + this.fetchParentAccess = fetchParentAccess; + + final EmbeddableMappingType virtualIdEmbeddable = embedded.getEmbeddableTypeDescriptor(); + this.representationEmbeddable = embedded.getMappedIdEmbeddableTypeDescriptor(); + this.representationStrategy = representationEmbeddable.getRepresentationStrategy(); + this.hasIdClass = embedded.hasContainingClass() && virtualIdEmbeddable != representationEmbeddable; + + final int size = virtualIdEmbeddable.getNumberOfFetchables(); + this.virtualIdState = new Object[ size ]; + this.idClassState = new Object[ size ]; + this.assemblers = arrayList( size ); + + this.sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory(); + initializeAssemblers( resultDescriptor, creationState, virtualIdEmbeddable ); + } + + + protected void initializeAssemblers( + EmbeddableResultGraphNode resultDescriptor, + AssemblerCreationState creationState, + EmbeddableMappingType embeddableTypeDescriptor) { + final int size = embeddableTypeDescriptor.getNumberOfFetchables(); + for ( int i = 0; i < size; i++ ) { + final Fetchable stateArrayContributor = embeddableTypeDescriptor.getFetchable( i ); + final Fetch fetch = resultDescriptor.findFetch( stateArrayContributor ); + + final DomainResultAssembler stateAssembler = fetch == null + ? new NullValueAssembler<>( stateArrayContributor.getJavaType() ) + : fetch.createAssembler( this, creationState ); + + assemblers.add( stateAssembler ); + } + } + + @Override + public EmbeddableValuedModelPart getInitializedPart() { + return embedded; + } + + @Override + public FetchParentAccess getFetchParentAccess() { + return fetchParentAccess; + } + + public NavigablePath getNavigablePath() { + return navigablePath; + } + + @Override + public Object getCompositeInstance() { + return compositeInstance; + } + + @Override + public FetchParentAccess findFirstEntityDescriptorAccess() { + if ( fetchParentAccess == null ) { + return null; + } + return fetchParentAccess.findFirstEntityDescriptorAccess(); + } + + @Override + public EntityInitializer findFirstEntityInitializer() { + final FetchParentAccess firstEntityDescriptorAccess = findFirstEntityDescriptorAccess(); + if ( firstEntityDescriptorAccess == null ) { + return null; + } + return firstEntityDescriptorAccess.findFirstEntityInitializer(); + } + + @Override + public void resolveKey(RowProcessingState processingState) { + // nothing to do + } + + @Override + public void resolveInstance(RowProcessingState processingState) { + // nothing to do + } + + @Override + public void initializeInstance(RowProcessingState processingState) { + EmbeddableLoadingLogger.EMBEDDED_LOAD_LOGGER.debugf( "Initializing composite instance [%s]", navigablePath ); + + switch ( state ) { + case NULL: + return; + case INITIAL: + // If we don't have an id class and this is a find by id lookup, we just use that instance + if ( !hasIdClass && processingState.getEntityId() != null + && navigablePath.getParent().getParent() == null + && navigablePath instanceof EntityIdentifierNavigablePath ) { + compositeInstance = processingState.getEntityId(); + state = State.INJECTED; + return; + } + // We need to possibly wrap the processing state if the embeddable is within an aggregate + processingState = wrapProcessingState( processingState ); + extractRowState( processingState ); + if ( state == State.NULL ) { + return; + } + else { + compositeInstance = representationStrategy.getInstantiator().instantiate( this, sessionFactory ); + } + case EXTRACTED: + final Object parentInstance; + if ( fetchParentAccess != null && ( parentInstance = fetchParentAccess.getInitializedInstance() ) != null ) { + notifyResolutionListeners( compositeInstance ); + + final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( parentInstance ); + // If the composite instance has a lazy initializer attached, this means that the embeddable is actually virtual + // and the compositeInstance == entity, so we have to inject the row state into the entity when it finishes resolution + if ( lazyInitializer != null ) { + final Initializer parentInitializer = processingState.resolveInitializer( navigablePath.getParent() ); + if ( parentInitializer != this ) { + ( (FetchParentAccess) parentInitializer ).registerResolutionListener( (entity) -> { + embedded.getVirtualIdEmbeddable().setValues( entity, virtualIdState ); + state = State.INJECTED; + } ); + } + else { + assert false; + // At this point, createEmptyCompositesEnabled is always true, so we generate + // the composite instance. + // + // NOTE: `valuesAccess` is set to null to indicate that all values are null, + // as opposed to returning the all-null value array. the instantiator + // interprets that as the values are not known or were all null. + final Object target = representationStrategy + .getInstantiator() + .instantiate( this, sessionFactory); + + state = State.INJECTED; + lazyInitializer.setImplementation( target ); + } + } + else { + embedded.getVirtualIdEmbeddable().setValues( parentInstance, virtualIdState ); + state = State.INJECTED; + } + } + } + } + + private void extractRowState(RowProcessingState processingState) { + state = State.NULL; + for ( int i = 0; i < assemblers.size(); i++ ) { + final DomainResultAssembler assembler = assemblers.get( i ); + final Object contributorValue = assembler.assemble( + processingState, + processingState.getJdbcValuesSourceProcessingState().getProcessingOptions() + ); + + if ( contributorValue == null ) { + // This is a key and there is a null part, the whole thing has to be turned into null + return; + } + if ( contributorValue == BATCH_PROPERTY ) { + virtualIdState[i] = null; + idClassState[i] = null; + } + else { + virtualIdState[i] = contributorValue; + idClassState[i] = contributorValue; + if ( hasIdClass ) { + final AttributeMapping virtualIdAttribute = embedded.getEmbeddableTypeDescriptor().getAttributeMapping( i ); + final AttributeMapping mappedIdAttribute = representationEmbeddable.getAttributeMapping( i ); + if ( virtualIdAttribute instanceof ToOneAttributeMapping + && !( mappedIdAttribute instanceof ToOneAttributeMapping ) ) { + final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) virtualIdAttribute; + final ForeignKeyDescriptor fkDescriptor = toOneAttributeMapping.getForeignKeyDescriptor(); + final Object associationKey = fkDescriptor.getAssociationKeyFromSide( + virtualIdState[i], + toOneAttributeMapping.getSideNature().inverse(), + processingState.getSession() + ); + idClassState[i] = associationKey; + } + } + } + } + state = State.EXTRACTED; + } + + @Override + public Object[] getValues() { + return state == State.NULL ? null : idClassState; + } + + @Override + public T getValue(int i, Class clazz) { + return state == State.NULL ? null : clazz.cast( idClassState[i] ); + } + + @Override + public Object getOwner() { + return fetchParentAccess.getInitializedInstance(); + } + + @Override + public void finishUpRow(RowProcessingState rowProcessingState) { + compositeInstance = null; + state = State.INITIAL; + + clearResolutionListeners(); + } + + @Override + public String toString() { + return getClass().getSimpleName() + "(" + navigablePath + ") : `" + getInitializedPart().getJavaType().getJavaTypeClass() + "`"; + } + + enum State { + INITIAL, + EXTRACTED, + NULL, + INJECTED + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableForeignKeyResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableForeignKeyResultImpl.java index 032c3b577f..8824861aff 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableForeignKeyResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/EmbeddableForeignKeyResultImpl.java @@ -10,6 +10,7 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.ForeignKeyDescriptor; import org.hibernate.metamodel.mapping.EmbeddableMappingType; +import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.results.graph.AbstractFetchParent; @@ -98,7 +99,9 @@ public DomainResultAssembler createResultAssembler( final EmbeddableInitializer initializer = creationState.resolveInitializer( getNavigablePath(), getReferencedModePart(), - () -> new EmbeddableResultInitializer( this, parentAccess, creationState ) + () -> getReferencedModePart() instanceof NonAggregatedIdentifierMapping + ? new NonAggregatedIdentifierMappingResultInitializer( this, null, creationState ) + : new EmbeddableResultInitializer( this, null, creationState ) ).asEmbeddableInitializer(); assert initializer != null; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java index 51b5ed7fba..7b1ce337aa 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NestedRowProcessingState.java @@ -6,13 +6,17 @@ */ package org.hibernate.sql.results.graph.embeddable.internal; +import org.hibernate.engine.spi.CollectionKey; +import org.hibernate.engine.spi.EntityKey; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterBindings; +import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor; import org.hibernate.spi.NavigablePath; import org.hibernate.sql.exec.internal.BaseExecutionContext; import org.hibernate.sql.exec.spi.Callback; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.entity.EntityFetch; +import org.hibernate.sql.results.graph.entity.LoadingEntityEntry; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.sql.results.spi.RowReader; @@ -89,8 +93,43 @@ public QueryParameterBindings getQueryParameterBindings() { return processingState.getQueryParameterBindings(); } + @Override + public boolean isScrollResult(){ + return processingState.isScrollResult(); + } + @Override public Callback getCallback() { return processingState.getCallback(); } + + @Override + public CollectionKey getCollectionKey() { + return processingState.getCollectionKey(); + } + + @Override + public Object getEntityInstance() { + return processingState.getEntityInstance(); + } + + @Override + public Object getEntityId() { + return processingState.getEntityId(); + } + + @Override + public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) { + processingState.registerLoadingEntityEntry( entityKey, entry ); + } + + @Override + public void afterStatement(LogicalConnectionImplementor logicalConnection) { + processingState.afterStatement( logicalConnection ); + } + + @Override + public boolean hasQueryExecutionToBeAddedToStatistics() { + return processingState.hasQueryExecutionToBeAddedToStatistics(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingFetch.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingFetch.java new file mode 100644 index 0000000000..45c61c9bb9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingFetch.java @@ -0,0 +1,41 @@ +/* + * 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.embeddable.internal; + +import org.hibernate.engine.FetchTiming; +import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping; +import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.FetchParentAccess; +import org.hibernate.sql.results.graph.Initializer; +import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; + +public class NonAggregatedIdentifierMappingFetch extends EmbeddableFetchImpl { + public NonAggregatedIdentifierMappingFetch( + NavigablePath navigablePath, + NonAggregatedIdentifierMapping embeddedPartDescriptor, + FetchParent fetchParent, + FetchTiming fetchTiming, + boolean hasTableGroup, + DomainResultCreationState creationState) { + super( navigablePath, embeddedPartDescriptor, fetchParent, fetchTiming, hasTableGroup, creationState ); + } + + public NonAggregatedIdentifierMappingFetch(EmbeddableFetchImpl original) { + super( original ); + } + + @Override + protected Initializer buildEmbeddableFetchInitializer( + FetchParentAccess parentAccess, + EmbeddableResultGraphNode embeddableFetch, + AssemblerCreationState creationState) { + return new NonAggregatedIdentifierMappingFetchInitializer( parentAccess, this, creationState ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingFetchInitializer.java new file mode 100644 index 0000000000..b93f05e6ca --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingFetchInitializer.java @@ -0,0 +1,31 @@ +/* + * 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.embeddable.internal; + +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.FetchParentAccess; +import org.hibernate.sql.results.graph.embeddable.AbstractEmbeddableInitializer; +import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; + +/** + * @author Steve Ebersole + */ +public class NonAggregatedIdentifierMappingFetchInitializer + extends AbstractNonAggregatedIdentifierMappingInitializer { + public NonAggregatedIdentifierMappingFetchInitializer( + FetchParentAccess fetchParentAccess, + EmbeddableResultGraphNode resultDescriptor, + AssemblerCreationState creationState) { + super( resultDescriptor, fetchParentAccess, creationState ); + } + + @Override + public Object getParentKey() { + return findFirstEntityDescriptorAccess().getParentKey(); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingResult.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingResult.java new file mode 100644 index 0000000000..c271bdce2e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingResult.java @@ -0,0 +1,45 @@ +/* + * 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.embeddable.internal; + +import org.hibernate.metamodel.mapping.NonAggregatedIdentifierMapping; +import org.hibernate.spi.NavigablePath; +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.DomainResultAssembler; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.FetchParentAccess; +import org.hibernate.sql.results.graph.embeddable.EmbeddableInitializer; + +public class NonAggregatedIdentifierMappingResult extends EmbeddableResultImpl { + public NonAggregatedIdentifierMappingResult( + NavigablePath navigablePath, + NonAggregatedIdentifierMapping modelPart, + String resultVariable, + DomainResultCreationState creationState) { + super( navigablePath, modelPart, resultVariable, creationState ); + } + + @Override + public DomainResultAssembler createResultAssembler( + FetchParentAccess parentAccess, + AssemblerCreationState creationState) { + final EmbeddableInitializer initializer = creationState.resolveInitializer( + getNavigablePath().append( "{embeddable_result}" ), + getReferencedModePart(), + () -> new NonAggregatedIdentifierMappingResultInitializer( + this, + parentAccess, + creationState + ) + ).asEmbeddableInitializer(); + + assert initializer != null; + + //noinspection unchecked + return new EmbeddableAssembler( initializer ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingResultInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingResultInitializer.java new file mode 100644 index 0000000000..bb00d079ed --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/embeddable/internal/NonAggregatedIdentifierMappingResultInitializer.java @@ -0,0 +1,33 @@ +/* + * 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.embeddable.internal; + +import org.hibernate.sql.results.graph.AssemblerCreationState; +import org.hibernate.sql.results.graph.FetchParentAccess; +import org.hibernate.sql.results.graph.embeddable.EmbeddableResultGraphNode; + +/** + * @author Steve Ebersole + */ +public class NonAggregatedIdentifierMappingResultInitializer extends AbstractNonAggregatedIdentifierMappingInitializer { + public NonAggregatedIdentifierMappingResultInitializer( + EmbeddableResultGraphNode resultDescriptor, + FetchParentAccess parentAccess, + AssemblerCreationState creationState) { + super( resultDescriptor, parentAccess, creationState ); + } + + @Override + public Object getParentKey() { + return findFirstEntityDescriptorAccess().getParentKey(); + } + + @Override + public String toString() { + return "EmbeddableResultInitializer(" + getNavigablePath() + ")"; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java index cf4943d146..be8e017427 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java @@ -52,6 +52,7 @@ import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.basic.BasicResultAssembler; +import org.hibernate.sql.results.graph.embeddable.internal.EmbeddableAssembler; import org.hibernate.sql.results.internal.NullValueAssembler; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState; @@ -524,6 +525,13 @@ else if ( entityInstanceFromExecutionContext != null ) { // look to see if another initializer from a parent load context or an earlier // initializer is already loading the entity entityInstance = resolveInstance( entityIdentifier, existingLoadingEntry, rowProcessingState ); + if ( isOwningInitializer && !isInitialized && identifierAssembler instanceof EmbeddableAssembler ) { + // If this is the owning initializer and the returned object is not initialized, + // this means that the entity instance was just instantiated. + // In this case, we want to call "assemble" and hence "initializeInstance" on the initializer + // for possibly non-aggregated identifier mappings, so inject the virtual id representation + identifierAssembler.assemble( rowProcessingState ); + } } upgradeLockMode( rowProcessingState ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowProcessingStateStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowProcessingStateStandardImpl.java index 7050d0423f..4955551998 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowProcessingStateStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/internal/RowProcessingStateStandardImpl.java @@ -7,6 +7,8 @@ package org.hibernate.sql.results.internal; import org.hibernate.engine.spi.CollectionKey; +import org.hibernate.engine.spi.EntityKey; +import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor; import org.hibernate.spi.NavigablePath; import org.hibernate.query.spi.QueryOptions; import org.hibernate.query.spi.QueryParameterBindings; @@ -15,6 +17,7 @@ import org.hibernate.sql.exec.spi.ExecutionContext; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.sql.results.graph.entity.EntityFetch; +import org.hibernate.sql.results.graph.entity.LoadingEntityEntry; import org.hibernate.sql.results.jdbc.internal.JdbcValuesCacheHit; import org.hibernate.sql.results.jdbc.internal.JdbcValuesSourceProcessingStateStandardImpl; import org.hibernate.sql.results.jdbc.spi.JdbcValues; @@ -138,6 +141,11 @@ public QueryParameterBindings getQueryParameterBindings() { return getJdbcValuesSourceProcessingState().getExecutionContext().getQueryParameterBindings(); } + @Override + public boolean isScrollResult(){ + return executionContext.isScrollResult(); + } + @Override public Callback getCallback() { return executionContext.getCallback(); @@ -148,6 +156,31 @@ public CollectionKey getCollectionKey() { return executionContext.getCollectionKey(); } + @Override + public Object getEntityInstance() { + return executionContext.getEntityInstance(); + } + + @Override + public Object getEntityId() { + return executionContext.getEntityId(); + } + + @Override + public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) { + executionContext.registerLoadingEntityEntry( entityKey, entry ); + } + + @Override + public void afterStatement(LogicalConnectionImplementor logicalConnection) { + executionContext.afterStatement( logicalConnection ); + } + + @Override + public boolean hasQueryExecutionToBeAddedToStatistics() { + return executionContext.hasQueryExecutionToBeAddedToStatistics(); + } + @Override public Initializer resolveInitializer(NavigablePath path) { return this.initializers.resolveInitializer( path );