HHH-18689 Maintain proxy targets when converting cache entries

This commit is contained in:
Christian Beikov 2024-10-07 17:06:05 +02:00
parent c7f8813b70
commit 9622f1965b
2 changed files with 65 additions and 37 deletions

View File

@ -5,10 +5,16 @@
package org.hibernate.engine.internal; package org.hibernate.engine.internal;
import org.hibernate.LockMode; import org.hibernate.LockMode;
import org.hibernate.engine.spi.EntityEntry;
import org.hibernate.engine.spi.EntityHolder;
import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status; import org.hibernate.engine.spi.Status;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.LazyInitializer;
import static org.hibernate.proxy.HibernateProxy.extractLazyInitializer;
/** /**
* Functionality relating to the Hibernate two-phase loading process, that may be reused by persisters * Functionality relating to the Hibernate two-phase loading process, that may be reused by persisters
@ -37,16 +43,27 @@ public final class TwoPhaseLoad {
final LockMode lockMode, final LockMode lockMode,
final Object version, final Object version,
final SharedSessionContractImplementor session) { final SharedSessionContractImplementor session) {
session.getPersistenceContextInternal().addEntity( final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityHolder entityHolder = persistenceContext.addEntityHolder( key, object );
final EntityEntry entityEntry = persistenceContext.addEntry(
object, object,
Status.LOADING, Status.LOADING,
null, null,
key, null,
key.getIdentifier(),
version, version,
lockMode, lockMode,
true, true,
persister, persister,
false false
); );
entityHolder.setEntityEntry( entityEntry );
final Object proxy = entityHolder.getProxy();
if ( proxy != null ) {
// there is already a proxy for this impl
final LazyInitializer lazyInitializer = extractLazyInitializer( proxy );
assert lazyInitializer != null;
lazyInitializer.setImplementation( object );
}
} }
} }

View File

@ -31,6 +31,7 @@ import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper; import org.hibernate.pretty.MessageHelper;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.sql.results.LoadingLogger; import org.hibernate.sql.results.LoadingLogger;
import org.hibernate.stat.internal.StatsHelper; import org.hibernate.stat.internal.StatsHelper;
import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.stat.spi.StatisticsImplementor;
@ -377,16 +378,17 @@ public class CacheEntityLoaderHelper {
final EntityPersister subclassPersister = final EntityPersister subclassPersister =
factory.getRuntimeMetamodels().getMappingMetamodel() factory.getRuntimeMetamodels().getMappingMetamodel()
.getEntityDescriptor( entry.getSubclass() ); .getEntityDescriptor( entry.getSubclass() );
final PersistenceContext persistenceContext = source.getPersistenceContextInternal();
final EntityHolder oldHolder = persistenceContext.getEntityHolder( entityKey );
final Object entity; final Object entity;
if ( instanceToLoad != null ) { if ( instanceToLoad != null ) {
entity = instanceToLoad; entity = instanceToLoad;
} }
else { else {
final EntityHolder holder = source.getPersistenceContextInternal().getEntityHolder( entityKey ); if ( oldHolder != null && oldHolder.getEntity() != null ) {
if ( holder != null && holder.getEntity() != null ) {
// Use the entity which might already be // Use the entity which might already be
entity = holder.getEntity(); entity = oldHolder.getEntity();
} }
else { else {
entity = source.instantiate( subclassPersister, entityId ); entity = source.instantiate( subclassPersister, entityId );
@ -407,13 +409,34 @@ public class CacheEntityLoaderHelper {
} }
// make it circular-reference safe // make it circular-reference safe
TwoPhaseLoad.addUninitializedCachedEntity( final EntityHolder holder = persistenceContext.addEntityHolder( entityKey, entity );
entityKey, final Object proxy = holder.getProxy();
final boolean isReadOnly;
if ( proxy != null ) {
// there is already a proxy for this impl
// only set the status to read-only if the proxy is read-only
final LazyInitializer lazyInitializer = extractLazyInitializer( proxy );
assert lazyInitializer != null;
lazyInitializer.setImplementation( entity );
isReadOnly = lazyInitializer.isReadOnly();
}
else {
isReadOnly = source.isDefaultReadOnly();
}
holder.setEntityEntry(
persistenceContext.addEntry(
entity, entity,
subclassPersister, Status.LOADING,
LockMode.NONE, null,
null,
entityKey.getIdentifier(),
entry.getVersion(), entry.getVersion(),
source LockMode.NONE,
true,
persister,
false
)
); );
final Type[] types = subclassPersister.getPropertyTypes(); final Type[] types = subclassPersister.getPropertyTypes();
@ -438,20 +461,8 @@ public class CacheEntityLoaderHelper {
final Object version = getVersion( values, subclassPersister ); final Object version = getVersion( values, subclassPersister );
LOG.tracef( "Cached Version : %s", version ); LOG.tracef( "Cached Version : %s", version );
final PersistenceContext persistenceContext = source.getPersistenceContext(); holder.setEntityEntry(
persistenceContext.addEntry(
final Object proxy = persistenceContext.getProxy( entityKey );
final boolean isReadOnly;
if ( proxy != null ) {
// there is already a proxy for this impl
// only set the status to read-only if the proxy is read-only
isReadOnly = extractLazyInitializer( proxy ).isReadOnly();
}
else {
isReadOnly = source.isDefaultReadOnly();
}
final EntityEntry entityEntry = persistenceContext.addEntry(
entity, entity,
isReadOnly ? Status.READ_ONLY : Status.MANAGED, isReadOnly ? Status.READ_ONLY : Status.MANAGED,
values, values,
@ -462,8 +473,8 @@ public class CacheEntityLoaderHelper {
true, true,
subclassPersister, subclassPersister,
false false
)
); );
persistenceContext.getEntityHolder( entityKey ).setEntityEntry( entityEntry );
subclassPersister.afterInitialize( entity, source ); subclassPersister.afterInitialize( entity, source );
persistenceContext.initializeNonLazyCollections(); persistenceContext.initializeNonLazyCollections();