Skip to content

Commit

Permalink
HHH-18719 Previous row state reuse can provide detaches entities to t…
Browse files Browse the repository at this point in the history
…he consumer
  • Loading branch information
dreab8 committed Oct 22, 2024
1 parent 77b36f9 commit d94087e
Show file tree
Hide file tree
Showing 5 changed files with 40 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
import static org.hibernate.engine.internal.ManagedTypeHelper.asManagedEntity;
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptable;
import static org.hibernate.engine.internal.ManagedTypeHelper.isPersistentAttributeInterceptable;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;

/**
* A <em>stateful</em> implementation of the {@link PersistenceContext} contract, meaning that we maintain this
Expand Down Expand Up @@ -231,8 +232,14 @@ public void clear() {
if ( entitiesByKey != null ) {
//Strictly avoid lambdas in this case
for ( EntityHolderImpl value : entitiesByKey.values() ) {
if ( value != null && value.proxy != null ) {
HibernateProxy.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();
}
}
}
}
}
Expand Down Expand Up @@ -2243,6 +2250,11 @@ public boolean isEventuallyInitialized() {
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 );
}
Expand All @@ -2255,7 +2267,8 @@ public static EntityHolderImpl forEntity(EntityKey entityKey, EntityPersister de
enum EntityHolderState {
UNINITIALIZED,
ENHANCED_PROXY,
INITIALIZED
INITIALIZED,
DETACHED
}

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

@Override
public EntityHolder detachEntity(EntityKey key) {
final EntityHolderImpl entityHolder = removeEntityHolder( key );
if ( entityHolder != null ) {
entityHolder.state = EntityHolderState.DETACHED;
}
return entityHolder;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -67,4 +67,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();
}
Original file line number Diff line number Diff line change
Expand Up @@ -864,4 +864,12 @@ EntityHolder claimEntityHolderIfPossible(
* @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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public void onEvict(EvictEvent event) throws HibernateException {
.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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -565,7 +565,7 @@ protected void resolveKey(EntityInitializerData data, boolean entityKeyOnly) {
}

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 );
Expand Down

0 comments on commit d94087e

Please sign in to comment.