HHH-18719 Previous row state reuse can provide detaches entities to the consumer

This commit is contained in:
Andrea Boriero 2024-10-17 11:24:24 +02:00 committed by Andrea Boriero
parent 96c61c3837
commit 356b7f54bb
5 changed files with 39 additions and 5 deletions

View File

@ -231,8 +231,14 @@ public class StatefulPersistenceContext implements PersistenceContext {
if ( entitiesByKey != null ) {
//Strictly avoid lambdas in this case
for ( EntityHolderImpl value : entitiesByKey.values() ) {
if ( value != null && value.proxy != null ) {
extractLazyInitializer( value.proxy ).unsetSession();
if ( value != null ) {
value.state = EntityHolderState.DETACHED;
if ( value.proxy != null ) {
final LazyInitializer lazyInitializer = extractLazyInitializer( value.proxy );
if ( lazyInitializer != null ) {
lazyInitializer.unsetSession();
}
}
}
}
}
@ -2238,6 +2244,11 @@ public class StatefulPersistenceContext implements PersistenceContext {
return state == EntityHolderState.INITIALIZED || entityInitializer != null;
}
@Override
public boolean isDetached() {
return state == EntityHolderState.DETACHED;
}
public static EntityHolderImpl forProxy(EntityKey entityKey, EntityPersister descriptor, Object proxy) {
return new EntityHolderImpl( entityKey, descriptor, null, proxy );
}
@ -2250,7 +2261,8 @@ public class StatefulPersistenceContext implements PersistenceContext {
enum EntityHolderState {
UNINITIALIZED,
ENHANCED_PROXY,
INITIALIZED
INITIALIZED,
DETACHED
}
// NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -2266,4 +2278,13 @@ public class StatefulPersistenceContext implements PersistenceContext {
return naturalIdResolutions;
}
@Override
public EntityHolder detachEntity(EntityKey key) {
final EntityHolderImpl entityHolder = removeEntityHolder( key );
if ( entityHolder != null ) {
entityHolder.state = EntityHolderState.DETACHED;
}
return entityHolder;
}
}

View File

@ -65,4 +65,9 @@ public interface EntityHolder {
* Whether the entity is already initialized or will be initialized through an initializer eventually.
*/
boolean isEventuallyInitialized();
/**
* Whether the entity is detached.
*/
boolean isDetached();
}

View File

@ -844,4 +844,12 @@ public interface PersistenceContext {
* @return This persistence context's natural-id helper
*/
NaturalIdResolutions getNaturalIdResolutions();
/**
Remove the {@link EntityHolder} and set its state to DETACHED
*/
default @Nullable EntityHolder detachEntity(EntityKey key) {
EntityHolder entityHolder = removeEntityHolder( key );
return entityHolder;
}
}

View File

@ -57,7 +57,7 @@ public class DefaultEvictEventListener implements EvictEventListener {
.getMappingMetamodel()
.getEntityDescriptor( lazyInitializer.getEntityName() );
final EntityKey key = source.generateEntityKey( id, persister );
final EntityHolder holder = persistenceContext.removeEntityHolder( key );
final EntityHolder holder = persistenceContext.detachEntity( key );
// if the entity has been evicted then its holder is null
if ( holder != null && !lazyInitializer.isUninitialized() ) {
final Object entity = holder.getEntity();

View File

@ -578,7 +578,7 @@ public class EntityInitializerImpl extends AbstractInitializer<EntityInitializer
}
if ( oldEntityKey != null && previousRowReuse && oldEntityInstance != null
&& areKeysEqual( oldEntityKey.getIdentifier(), id ) ) {
&& areKeysEqual( oldEntityKey.getIdentifier(), id ) && !oldEntityHolder.isDetached() ) {
data.setState( State.INITIALIZED );
data.entityKey = oldEntityKey;
data.setInstance( oldEntityInstance );