Skip to content

Commit d94087e

Browse files
committed
HHH-18719 Previous row state reuse can provide detaches entities to the consumer
1 parent 77b36f9 commit d94087e

File tree

5 files changed

+40
-5
lines changed

5 files changed

+40
-5
lines changed

hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java

Lines changed: 25 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@
7878
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
7979
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
8080
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
81+
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
8182

8283
/**
8384
* A <em>stateful</em> implementation of the {@link PersistenceContext} contract, meaning that we maintain this
@@ -231,8 +232,14 @@ public void clear() {
231232
if ( entitiesByKey != null ) {
232233
//Strictly avoid lambdas in this case
233234
for ( EntityHolderImpl value : entitiesByKey.values() ) {
234-
if ( value != null && value.proxy != null ) {
235-
HibernateProxy.extractLazyInitializer( value.proxy ).unsetSession();
235+
if ( value != null ) {
236+
value.state = EntityHolderState.DETACHED;
237+
if ( value.proxy != null ) {
238+
final LazyInitializer lazyInitializer = extractLazyInitializer( value.proxy );
239+
if ( lazyInitializer != null ) {
240+
lazyInitializer.unsetSession();
241+
}
242+
}
236243
}
237244
}
238245
}
@@ -2243,6 +2250,11 @@ public boolean isEventuallyInitialized() {
22432250
return state == EntityHolderState.INITIALIZED || entityInitializer != null;
22442251
}
22452252

2253+
@Override
2254+
public boolean isDetached() {
2255+
return state == EntityHolderState.DETACHED;
2256+
}
2257+
22462258
public static EntityHolderImpl forProxy(EntityKey entityKey, EntityPersister descriptor, Object proxy) {
22472259
return new EntityHolderImpl( entityKey, descriptor, null, proxy );
22482260
}
@@ -2255,7 +2267,8 @@ public static EntityHolderImpl forEntity(EntityKey entityKey, EntityPersister de
22552267
enum EntityHolderState {
22562268
UNINITIALIZED,
22572269
ENHANCED_PROXY,
2258-
INITIALIZED
2270+
INITIALIZED,
2271+
DETACHED
22592272
}
22602273

22612274
// NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@@ -2271,4 +2284,13 @@ public NaturalIdResolutions getNaturalIdResolutions() {
22712284
return naturalIdResolutions;
22722285
}
22732286

2287+
@Override
2288+
public EntityHolder detachEntity(EntityKey key) {
2289+
final EntityHolderImpl entityHolder = removeEntityHolder( key );
2290+
if ( entityHolder != null ) {
2291+
entityHolder.state = EntityHolderState.DETACHED;
2292+
}
2293+
return entityHolder;
2294+
}
2295+
22742296
}

hibernate-core/src/main/java/org/hibernate/engine/spi/EntityHolder.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,4 +67,9 @@ public interface EntityHolder {
6767
* Whether the entity is already initialized or will be initialized through an initializer eventually.
6868
*/
6969
boolean isEventuallyInitialized();
70+
71+
/**
72+
* Whether the entity is detached.
73+
*/
74+
boolean isDetached();
7075
}

hibernate-core/src/main/java/org/hibernate/engine/spi/PersistenceContext.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -864,4 +864,12 @@ EntityHolder claimEntityHolderIfPossible(
864864
* @return This persistence context's natural-id helper
865865
*/
866866
NaturalIdResolutions getNaturalIdResolutions();
867+
868+
/**
869+
Remove the {@link EntityHolder} and set its state to DETACHED
870+
*/
871+
default @Nullable EntityHolder detachEntity(EntityKey key) {
872+
EntityHolder entityHolder = removeEntityHolder( key );
873+
return entityHolder;
874+
}
867875
}

hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public void onEvict(EvictEvent event) throws HibernateException {
5959
.getMappingMetamodel()
6060
.getEntityDescriptor( lazyInitializer.getEntityName() );
6161
final EntityKey key = source.generateEntityKey( id, persister );
62-
final EntityHolder holder = persistenceContext.removeEntityHolder( key );
62+
final EntityHolder holder = persistenceContext.detachEntity( key );
6363
// if the entity has been evicted then its holder is null
6464
if ( holder != null && !lazyInitializer.isUninitialized() ) {
6565
final Object entity = holder.getEntity();

hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityInitializerImpl.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ protected void resolveKey(EntityInitializerData data, boolean entityKeyOnly) {
565565
}
566566

567567
if ( oldEntityKey != null && previousRowReuse && oldEntityInstance != null
568-
&& areKeysEqual( oldEntityKey.getIdentifier(), id ) ) {
568+
&& areKeysEqual( oldEntityKey.getIdentifier(), id ) && !oldEntityHolder.isDetached() ) {
569569
data.setState( State.INITIALIZED );
570570
data.entityKey = oldEntityKey;
571571
data.setInstance( oldEntityInstance );

0 commit comments

Comments
 (0)