diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/DelayedCollectionAssembler.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/DelayedCollectionAssembler.java index acc4469e86..0033251d3f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/DelayedCollectionAssembler.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/DelayedCollectionAssembler.java @@ -22,6 +22,7 @@ import org.hibernate.sql.results.graph.collection.CollectionInitializer; import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.Initializer; +import org.hibernate.sql.results.graph.entity.EntityInitializer; import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions; import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; @@ -106,8 +107,18 @@ public class DelayedCollectionAssembler implements DomainResultAssembler { @Override public void resolveInstance(RowProcessingState rowProcessingState) { if ( collectionKey != null ) { + EntityInitializer entityInitializer = getEntityInitializer( rowProcessingState ); + final SharedSessionContractImplementor session = rowProcessingState.getSession(); final PersistenceContext persistenceContext = session.getPersistenceContext(); + + final Object entityUsingInterceptor = persistenceContext.getEntity(entityInitializer.getEntityKey() ); + if ( entityUsingInterceptor != null ) { + return; + } + + final Object key = collectionKey.getKey(); + final LoadingCollectionEntry loadingEntry = persistenceContext.getLoadContexts() .findLoadingCollectionEntry( collectionKey ); final PersistentCollection registeredInstance = persistenceContext.getCollection( collectionKey ); @@ -122,16 +133,23 @@ public class DelayedCollectionAssembler implements DomainResultAssembler { return; } - this.instance = makePersistentCollection( fetchedMapping, collectionKey, rowProcessingState ); persistenceContext.addUninitializedCollection( getInitializingCollectionDescriptor(), instance, - collectionKey.getKey() + key ); } } + private EntityInitializer getEntityInitializer(RowProcessingState rowProcessingState) { + Initializer initializer = rowProcessingState.resolveInitializer( getNavigablePath().getParent() ); + while ( !( initializer instanceof EntityInitializer ) ) { + initializer = rowProcessingState.resolveInitializer( initializer.getNavigablePath().getParent() ); + } + return (EntityInitializer) initializer; + } + private static PersistentCollection makePersistentCollection( PluralAttributeMapping fetchedMapping, CollectionKey collectionKey, 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 090932731b..336193b6d4 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 @@ -196,6 +196,11 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces return entityKey.getIdentifier(); } + @Override + public EntityKey getEntityKey() { + return entityKey; + } + @Override public Object getParentKey() { return getKeyValue(); @@ -342,12 +347,23 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces ); } - final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); + final SharedSessionContractImplementor session = rowProcessingState + .getJdbcValuesSourceProcessingState() + .getSession(); + + final PersistenceContext persistenceContext = session.getPersistenceContext(); + + final Object existingEntity = persistenceContext.getEntity( entityKey ); + + if ( existingEntity != null ) { + entityInstance = existingEntity; + return; + } // look to see if another initializer from a parent load context or an earlier // initializer is already loading the entity - final LoadingEntityEntry existingLoadingEntry = session.getPersistenceContext() + final LoadingEntityEntry existingLoadingEntry = persistenceContext .getLoadContexts() .findLoadingEntityEntry( entityKey ); @@ -390,7 +406,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces if ( entityInstance == null ) { // see if it is managed in the Session already - final Object entity = session.getPersistenceContext().getEntity( entityKey ); + final Object entity = persistenceContext.getEntity( entityKey ); if ( entity != null ) { this.entityInstance = entity; } @@ -432,6 +448,13 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces return; } + final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); + final PersistenceContext persistenceContext = session.getPersistenceContext(); + + if ( persistenceContext.getEntity( entityKey ) != null ) { + return; + } + final Serializable entityIdentifier = entityKey.getIdentifier(); if ( EntityLoadingLogger.TRACE_ENABLED ) { @@ -441,8 +464,6 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces ); } - final SharedSessionContractImplementor session = rowProcessingState.getJdbcValuesSourceProcessingState().getSession(); - PersistenceContext persistenceContext = session.getPersistenceContext(); // todo (6.0): do we really need this check ? if ( persistenceContext.containsEntity( entityKey ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/EntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/EntityInitializer.java index e7e47d15de..acecb4344c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/EntityInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/EntityInitializer.java @@ -6,6 +6,7 @@ */ package org.hibernate.sql.results.graph.entity; +import org.hibernate.engine.spi.EntityKey; import org.hibernate.sql.results.graph.FetchParentAccess; import org.hibernate.sql.results.graph.Initializer; import org.hibernate.metamodel.mapping.ModelPart; @@ -61,4 +62,6 @@ public interface EntityInitializer extends Initializer, FetchParentAccess { } return entityInstance; } + + EntityKey getEntityKey(); } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchDelayedInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchDelayedInitializer.java index eeca135c13..09dd1ba21c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchDelayedInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchDelayedInitializer.java @@ -116,6 +116,11 @@ public class EntityFetchDelayedInitializer extends AbstractFetchParentAccess imp return entityInstance; } + @Override + public EntityKey getEntityKey() { + throw new NotYetImplementedFor6Exception( getClass() ); + } + @Override public Object getParentKey() { throw new NotYetImplementedFor6Exception( getClass() ); diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerSelectFetch.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerSelectFetch.java index 754779945b..99a566cddc 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerSelectFetch.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerSelectFetch.java @@ -9,6 +9,7 @@ package org.hibernate.sql.results.graph.entity.internal; import java.util.function.Consumer; import org.hibernate.NotYetImplementedFor6Exception; +import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.proxy.HibernateProxy; @@ -100,6 +101,11 @@ public class EntityInitializerSelectFetch extends AbstractFetchParentAccess impl return entityInstance; } + @Override + public EntityKey getEntityKey() { + throw new NotYetImplementedFor6Exception( getClass() ); + } + @Override public Object getParentKey() { throw new NotYetImplementedFor6Exception( getClass() );