diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java index c9b700fcd633..dd91a6c5420f 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java @@ -26,6 +26,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; +import static org.hibernate.internal.util.NullnessUtil.castNonNull; + /** * Base support for CollectionInitializer implementations that represent * an immediate initialization of some sort (join, select, batch, sub-select) @@ -141,7 +143,39 @@ public void resolveState(Data data) { public void resolveFromPreviousRow(Data data) { super.resolveFromPreviousRow( data ); if ( data.getState() == State.RESOLVED ) { - resolveKeySubInitializers( data ); + // The state is resolved, so we know a collection instance exists + final PersistentCollection collection = castNonNull( data.getCollectionInstance() ); + if ( collection.wasInitialized() ) { + // The collection was an already initialized instance, so we can set this to initialized + // and just resolve sub-initializers + resolveFromPreviouslyInitializedInstance( data ); + } + else { + resolveKeySubInitializers( data ); + } + } + } + + protected void resolveFromPreviouslyInitializedInstance(Data data) { + data.setState( State.INITIALIZED ); + if ( data.shallowCached ) { + initializeShallowCached( data ); + } + else { + resolveInstanceSubInitializers( data ); + } + final var rowProcessingState = data.getRowProcessingState(); + if ( rowProcessingState.needsResolveState() ) { + // Resolve the state of the identifier if result caching is enabled and this is not a query cache hit + if ( collectionKeyResultAssembler != null ) { + collectionKeyResultAssembler.resolveState( rowProcessingState ); + } + if ( !getInitializingCollectionDescriptor().useShallowQueryCacheLayout() ) { + if ( collectionValueKeyResultAssembler != null ) { + collectionValueKeyResultAssembler.resolveState( rowProcessingState ); + } + resolveCollectionContentState( rowProcessingState ); + } } } @@ -337,25 +371,7 @@ public void resolveInstance(Object instance, Data data) { } data.collectionValueKey = null; if ( collection.wasInitialized() ) { - data.setState( State.INITIALIZED ); - if ( data.shallowCached ) { - initializeShallowCached( data ); - } - else { - resolveInstanceSubInitializers( data ); - } - if ( rowProcessingState.needsResolveState() ) { - // Resolve the state of the identifier if result caching is enabled and this is not a query cache hit - if ( collectionKeyResultAssembler != null ) { - collectionKeyResultAssembler.resolveState( rowProcessingState ); - } - if ( !getInitializingCollectionDescriptor().useShallowQueryCacheLayout() ) { - if ( collectionValueKeyResultAssembler != null ) { - collectionValueKeyResultAssembler.resolveState( rowProcessingState ); - } - resolveCollectionContentState( rowProcessingState ); - } - } + resolveFromPreviouslyInitializedInstance( data ); } else { if ( data.shallowCached ) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedCollectionInitializationJoinFetchTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedCollectionInitializationJoinFetchTest.java index 5fd059dbeeaa..9a9d53a596b5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedCollectionInitializationJoinFetchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedCollectionInitializationJoinFetchTest.java @@ -69,6 +69,14 @@ public void testInitializedDetachedInstance(SessionFactoryScope scope) { } ); } + @Test + public void testExistingPersistentInstance(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final var entityA = session.find( EntityA.class, 1L ); + fetchQuery( new ArrayList<>( entityA.getB() ), session ); + } ); + } + @BeforeEach public void setUp(SessionFactoryScope scope) { scope.inTransaction( session -> { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedNonJoinedCollectionInitializationJoinFetchTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedNonJoinedCollectionInitializationJoinFetchTest.java index 836cbf45e6ef..40df08d61fc1 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedNonJoinedCollectionInitializationJoinFetchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedNonJoinedCollectionInitializationJoinFetchTest.java @@ -71,6 +71,14 @@ public void testInitializedDetachedInstance(SessionFactoryScope scope) { } ); } + @Test + public void testExistingPersistentInstance(SessionFactoryScope scope) { + scope.inTransaction( session -> { + final var entityA = session.find( EntityA.class, 1L ); + fetchQuery( new ArrayList<>( entityA.getB() ), session ); + } ); + } + @BeforeEach public void setUp(SessionFactoryScope scope) { scope.inTransaction( session -> {