Skip to content

Commit 87d7aa9

Browse files
committed
HHH-19915 Re-use existing initialized collection instance when reading from previous row
1 parent 0722f2c commit 87d7aa9

File tree

3 files changed

+52
-20
lines changed

3 files changed

+52
-20
lines changed

hibernate-core/src/main/java/org/hibernate/sql/results/graph/collection/internal/AbstractImmediateCollectionInitializer.java

Lines changed: 36 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@
2626

2727
import org.checkerframework.checker.nullness.qual.Nullable;
2828

29+
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
30+
2931
/**
3032
* Base support for CollectionInitializer implementations that represent
3133
* an immediate initialization of some sort (join, select, batch, sub-select)
@@ -141,7 +143,39 @@ public void resolveState(Data data) {
141143
public void resolveFromPreviousRow(Data data) {
142144
super.resolveFromPreviousRow( data );
143145
if ( data.getState() == State.RESOLVED ) {
144-
resolveKeySubInitializers( data );
146+
// The state is resolved, so we know a collection instance exists
147+
final PersistentCollection<?> collection = castNonNull( data.getCollectionInstance() );
148+
if ( collection.wasInitialized() ) {
149+
// The collection was an already initialized instance, so we can set this to initialized
150+
// and just resolve sub-initializers
151+
resolveFromPreviouslyInitializedInstance( data );
152+
}
153+
else {
154+
resolveKeySubInitializers( data );
155+
}
156+
}
157+
}
158+
159+
protected void resolveFromPreviouslyInitializedInstance(Data data) {
160+
data.setState( State.INITIALIZED );
161+
if ( data.shallowCached ) {
162+
initializeShallowCached( data );
163+
}
164+
else {
165+
resolveInstanceSubInitializers( data );
166+
}
167+
final var rowProcessingState = data.getRowProcessingState();
168+
if ( rowProcessingState.needsResolveState() ) {
169+
// Resolve the state of the identifier if result caching is enabled and this is not a query cache hit
170+
if ( collectionKeyResultAssembler != null ) {
171+
collectionKeyResultAssembler.resolveState( rowProcessingState );
172+
}
173+
if ( !getInitializingCollectionDescriptor().useShallowQueryCacheLayout() ) {
174+
if ( collectionValueKeyResultAssembler != null ) {
175+
collectionValueKeyResultAssembler.resolveState( rowProcessingState );
176+
}
177+
resolveCollectionContentState( rowProcessingState );
178+
}
145179
}
146180
}
147181

@@ -337,25 +371,7 @@ public void resolveInstance(Object instance, Data data) {
337371
}
338372
data.collectionValueKey = null;
339373
if ( collection.wasInitialized() ) {
340-
data.setState( State.INITIALIZED );
341-
if ( data.shallowCached ) {
342-
initializeShallowCached( data );
343-
}
344-
else {
345-
resolveInstanceSubInitializers( data );
346-
}
347-
if ( rowProcessingState.needsResolveState() ) {
348-
// Resolve the state of the identifier if result caching is enabled and this is not a query cache hit
349-
if ( collectionKeyResultAssembler != null ) {
350-
collectionKeyResultAssembler.resolveState( rowProcessingState );
351-
}
352-
if ( !getInitializingCollectionDescriptor().useShallowQueryCacheLayout() ) {
353-
if ( collectionValueKeyResultAssembler != null ) {
354-
collectionValueKeyResultAssembler.resolveState( rowProcessingState );
355-
}
356-
resolveCollectionContentState( rowProcessingState );
357-
}
358-
}
374+
resolveFromPreviouslyInitializedInstance( data );
359375
}
360376
else {
361377
if ( data.shallowCached ) {

hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedCollectionInitializationJoinFetchTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,14 @@ public void testInitializedDetachedInstance(SessionFactoryScope scope) {
6969
} );
7070
}
7171

72+
@Test
73+
public void testExistingPersistentInstance(SessionFactoryScope scope) {
74+
scope.inTransaction( session -> {
75+
final var entityA = session.find( EntityA.class, 1L );
76+
fetchQuery( new ArrayList<>( entityA.getB() ), session );
77+
} );
78+
}
79+
7280
@BeforeEach
7381
public void setUp(SessionFactoryScope scope) {
7482
scope.inTransaction( session -> {

hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/detached/collection/DetachedNonJoinedCollectionInitializationJoinFetchTest.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,14 @@ public void testInitializedDetachedInstance(SessionFactoryScope scope) {
7171
} );
7272
}
7373

74+
@Test
75+
public void testExistingPersistentInstance(SessionFactoryScope scope) {
76+
scope.inTransaction( session -> {
77+
final var entityA = session.find( EntityA.class, 1L );
78+
fetchQuery( new ArrayList<>( entityA.getB() ), session );
79+
} );
80+
}
81+
7482
@BeforeEach
7583
public void setUp(SessionFactoryScope scope) {
7684
scope.inTransaction( session -> {

0 commit comments

Comments
 (0)