HHH-17309 Get rid of LoadingEntityEntry
This commit is contained in:
parent
ec3efdbe39
commit
d8bad73f58
|
@ -52,6 +52,9 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
|
|||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.Status;
|
||||
import org.hibernate.event.service.spi.EventListenerGroup;
|
||||
import org.hibernate.event.spi.PostLoadEvent;
|
||||
import org.hibernate.event.spi.PostLoadEventListener;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.internal.util.collections.IdentityMap;
|
||||
|
@ -61,6 +64,9 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
import org.hibernate.pretty.MessageHelper;
|
||||
import org.hibernate.proxy.HibernateProxy;
|
||||
import org.hibernate.proxy.LazyInitializer;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||
import org.hibernate.sql.results.spi.LoadContexts;
|
||||
import org.hibernate.type.CollectionType;
|
||||
|
||||
|
@ -369,6 +375,42 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
return (Object[]) snapshot;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityHolder claimEntityHolderIfPossible(
|
||||
EntityKey key,
|
||||
Object entity,
|
||||
JdbcValuesSourceProcessingState processingState,
|
||||
EntityInitializer initializer) {
|
||||
EntityHolderImpl holder = EntityHolderImpl.forEntity( key, key.getPersister(), entity );
|
||||
final EntityHolderImpl oldHolder = getOrInitializeEntitiesByKey().putIfAbsent(
|
||||
key,
|
||||
holder
|
||||
);
|
||||
|
||||
if ( oldHolder != null ) {
|
||||
if ( entity != null ) {
|
||||
assert oldHolder.entity == null || oldHolder.entity == entity;
|
||||
oldHolder.entity = entity;
|
||||
}
|
||||
// Skip setting a new entity initializer if there already is one owner
|
||||
// Also skip if an entity exists which is different from the effective optional object.
|
||||
// The effective optional object is the current object to be refreshed,
|
||||
// which always needs re-initialization, even if already initialized
|
||||
if ( oldHolder.entityInitializer != null
|
||||
|| oldHolder.entity != null && oldHolder.state != EntityHolderState.ENHANCED_PROXY && (
|
||||
processingState.getProcessingOptions().getEffectiveOptionalObject() == null
|
||||
|| oldHolder.entity != processingState.getProcessingOptions().getEffectiveOptionalObject() )
|
||||
) {
|
||||
return oldHolder;
|
||||
}
|
||||
holder = oldHolder;
|
||||
}
|
||||
assert holder.entityInitializer == null || holder.entityInitializer == initializer;
|
||||
holder.entityInitializer = initializer;
|
||||
holder.processingState = processingState;
|
||||
return holder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityHolderImpl getEntityHolder(EntityKey key) {
|
||||
return entitiesByKey == null ? null : entitiesByKey.get( key );
|
||||
|
@ -380,11 +422,73 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(EntityKey key, Object entity) {
|
||||
final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent( key, EntityHolderImpl.forEntity( entity ) );
|
||||
if ( holder != null ) {
|
||||
holder.entity = entity;
|
||||
public void postLoad(JdbcValuesSourceProcessingState processingState, Consumer<EntityHolder> holderConsumer) {
|
||||
if ( entitiesByKey == null ) {
|
||||
return;
|
||||
}
|
||||
final Callback callback = processingState.getExecutionContext().getCallback();
|
||||
final EventListenerGroup<PostLoadEventListener> listenerGroup = getSession().getFactory()
|
||||
.getFastSessionServices()
|
||||
.eventListenerGroup_POST_LOAD;
|
||||
final PostLoadEvent postLoadEvent = getSession().isEventSource() ? new PostLoadEvent( getSession().asEventSource() ) : null;
|
||||
for ( Iterator<EntityHolderImpl> iterator = entitiesByKey.values().iterator(); iterator.hasNext(); ) {
|
||||
final EntityHolderImpl holder = iterator.next();
|
||||
if ( holder.processingState == processingState ) {
|
||||
if ( holderConsumer != null ) {
|
||||
holderConsumer.accept( holder );
|
||||
}
|
||||
if ( holder.entity == null ) {
|
||||
// It's possible that we tried to load an entity and found out it doesn't exist,
|
||||
// in which case we added an entry with a null proxy and entity.
|
||||
// Remove that empty entry on post load to avoid unwanted side effects
|
||||
iterator.remove();
|
||||
continue;
|
||||
}
|
||||
if ( postLoadEvent != null ) {
|
||||
postLoadEvent.reset();
|
||||
postLoadEvent.setEntity( holder.entity )
|
||||
.setId( holder.entityKey.getIdentifier() )
|
||||
.setPersister( holder.getDescriptor() );
|
||||
listenerGroup.fireEventOnEachListener(
|
||||
postLoadEvent,
|
||||
PostLoadEventListener::onPostLoad
|
||||
);
|
||||
}
|
||||
|
||||
if ( callback != null ) {
|
||||
callback.invokeAfterLoadActions(
|
||||
holder.getEntity(),
|
||||
holder.getDescriptor(),
|
||||
getSession()
|
||||
);
|
||||
if ( holder.reloaded ) {
|
||||
callback.invokeAfterLoadActions(
|
||||
holder.getEntity(),
|
||||
holder.getDescriptor(),
|
||||
getSession()
|
||||
);
|
||||
}
|
||||
}
|
||||
holder.processingState = null;
|
||||
holder.entityInitializer = null;
|
||||
holder.reloaded = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntity(EntityKey key, Object entity) {
|
||||
EntityHolderImpl holder = EntityHolderImpl.forEntity( key, key.getPersister(), entity );
|
||||
final EntityHolderImpl oldHolder = getOrInitializeEntitiesByKey().putIfAbsent(
|
||||
key,
|
||||
holder
|
||||
);
|
||||
if ( oldHolder != null ) {
|
||||
// assert oldHolder.entity == null || oldHolder.entity == entity;
|
||||
oldHolder.entity = entity;
|
||||
holder = oldHolder;
|
||||
}
|
||||
holder.state = EntityHolderState.INITIALIZED;
|
||||
final BatchFetchQueue fetchQueue = this.batchFetchQueue;
|
||||
if ( fetchQueue != null ) {
|
||||
fetchQueue.removeBatchLoadableEntityKey( key );
|
||||
|
@ -394,13 +498,13 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
@Override
|
||||
public Object getEntity(EntityKey key) {
|
||||
final EntityHolderImpl holder = entitiesByKey == null ? null : entitiesByKey.get( key );
|
||||
return holder == null ? null : holder.entity;
|
||||
return holder == null || holder.state == EntityHolderState.UNINITIALIZED ? null : holder.entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean containsEntity(EntityKey key) {
|
||||
final EntityHolderImpl holder = entitiesByKey == null ? null : entitiesByKey.get( key );
|
||||
return holder != null && holder.entity != null;
|
||||
return holder != null && holder.entity != null && holder.state != EntityHolderState.UNINITIALIZED;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -656,7 +760,7 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
// any earlier proxy takes precedence
|
||||
final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent(
|
||||
key,
|
||||
EntityHolderImpl.forProxy( proxy )
|
||||
EntityHolderImpl.forProxy( key, persister, proxy )
|
||||
);
|
||||
if ( holder != null && holder.proxy == null ) {
|
||||
holder.proxy = proxy;
|
||||
|
@ -803,10 +907,16 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
|
||||
@Override
|
||||
public void addEnhancedProxy(EntityKey key, PersistentAttributeInterceptable entity) {
|
||||
final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent( key, EntityHolderImpl.forEntity( entity ) );
|
||||
if ( holder != null ) {
|
||||
holder.entity = entity;
|
||||
EntityHolderImpl holder = EntityHolderImpl.forEntity( key, key.getPersister(), entity );
|
||||
final EntityHolderImpl oldHolder = getOrInitializeEntitiesByKey().putIfAbsent(
|
||||
key,
|
||||
holder
|
||||
);
|
||||
if ( oldHolder != null ) {
|
||||
oldHolder.entity = entity;
|
||||
holder = oldHolder;
|
||||
}
|
||||
holder.state = EntityHolderState.ENHANCED_PROXY;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -1094,7 +1204,10 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
|
||||
@Override
|
||||
public void addProxy(EntityKey key, Object proxy) {
|
||||
final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent( key, EntityHolderImpl.forProxy( proxy ) );
|
||||
final EntityHolderImpl holder = getOrInitializeEntitiesByKey().putIfAbsent(
|
||||
key,
|
||||
EntityHolderImpl.forProxy( key, key.getPersister(), proxy )
|
||||
);
|
||||
if ( holder != null ) {
|
||||
holder.proxy = proxy;
|
||||
}
|
||||
|
@ -1658,8 +1771,10 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
writeMapToStream( entitiesByKey, oos, "entitiesByKey", (entry, stream) -> {
|
||||
entry.getKey().serialize( stream );
|
||||
final EntityHolderImpl holder = entry.getValue();
|
||||
stream.writeObject( holder.descriptor.getEntityName() );
|
||||
stream.writeObject( holder.entity );
|
||||
stream.writeObject( holder.proxy );
|
||||
stream.writeObject( holder.state );
|
||||
} );
|
||||
writeMapToStream( entitiesByUniqueKey, oos, "entitiesByUniqueKey", (entry, stream) -> {
|
||||
entry.getKey().serialize( stream );
|
||||
|
@ -1775,9 +1890,12 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
rtn.entitiesByKey = CollectionHelper.mapOfSize(Math.max(count, INIT_COLL_SIZE));
|
||||
for ( int i = 0; i < count; i++ ) {
|
||||
final EntityKey ek = EntityKey.deserialize( ois, sfi );
|
||||
final EntityPersister persister = sfi.getMappingMetamodel().getEntityDescriptor( (String) ois.readObject() );
|
||||
final Object entity = ois.readObject();
|
||||
final Object proxy = ois.readObject();
|
||||
final EntityHolderImpl holder = EntityHolderImpl.forEntity( entity );
|
||||
final EntityHolderState state = (EntityHolderState) ois.readObject();
|
||||
final EntityHolderImpl holder = EntityHolderImpl.forEntity( ek, persister, entity );
|
||||
holder.state = state;
|
||||
if ( proxy != null ) {
|
||||
final LazyInitializer lazyInitializer = HibernateProxy.extractLazyInitializer( proxy );
|
||||
if ( lazyInitializer != null ) {
|
||||
|
@ -2014,12 +2132,32 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
}
|
||||
|
||||
private static class EntityHolderImpl implements EntityHolder, Serializable {
|
||||
private final EntityKey entityKey;
|
||||
private final EntityPersister descriptor;
|
||||
Object entity;
|
||||
Object proxy;
|
||||
EntityInitializer entityInitializer;
|
||||
JdbcValuesSourceProcessingState processingState;
|
||||
boolean reloaded;
|
||||
EntityHolderState state;
|
||||
|
||||
private EntityHolderImpl(Object entity, Object proxy) {
|
||||
private EntityHolderImpl(EntityKey entityKey, EntityPersister descriptor, Object entity, Object proxy) {
|
||||
assert entityKey != null && descriptor != null;
|
||||
this.entityKey = entityKey;
|
||||
this.descriptor = descriptor;
|
||||
this.entity = entity;
|
||||
this.proxy = proxy;
|
||||
this.state = EntityHolderState.UNINITIALIZED;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityKey getEntityKey() {
|
||||
return entityKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityPersister getDescriptor() {
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -2032,13 +2170,36 @@ public class StatefulPersistenceContext implements PersistenceContext {
|
|||
return proxy;
|
||||
}
|
||||
|
||||
public static EntityHolderImpl forProxy(Object proxy) {
|
||||
return new EntityHolderImpl( null, proxy );
|
||||
@Override
|
||||
public EntityInitializer getEntityInitializer() {
|
||||
return entityInitializer;
|
||||
}
|
||||
|
||||
public static EntityHolderImpl forEntity(Object entity) {
|
||||
return new EntityHolderImpl( entity, null );
|
||||
@Override
|
||||
public void markAsReloaded(JdbcValuesSourceProcessingState processingState) {
|
||||
assert this.processingState == null;
|
||||
this.reloaded = true;
|
||||
this.processingState = processingState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEventuallyInitialized() {
|
||||
return state == EntityHolderState.INITIALIZED || entityInitializer != null;
|
||||
}
|
||||
|
||||
public static EntityHolderImpl forProxy(EntityKey entityKey, EntityPersister descriptor, Object proxy) {
|
||||
return new EntityHolderImpl( entityKey, descriptor, null, proxy );
|
||||
}
|
||||
|
||||
public static EntityHolderImpl forEntity(EntityKey entityKey, EntityPersister descriptor, Object entity) {
|
||||
return new EntityHolderImpl( entityKey, descriptor, entity, null );
|
||||
}
|
||||
}
|
||||
|
||||
enum EntityHolderState {
|
||||
UNINITIALIZED,
|
||||
ENHANCED_PROXY,
|
||||
INITIALIZED
|
||||
}
|
||||
|
||||
// NATURAL ID RESOLUTION HANDLING ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -6,12 +6,54 @@
|
|||
*/
|
||||
package org.hibernate.engine.spi;
|
||||
|
||||
public interface EntityHolder {
|
||||
Object getEntity();
|
||||
Object getProxy();
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||
|
||||
default Object getManagedObject() {
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Holder for an entry in the {@link PersistenceContext} for an {@link EntityKey}.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
@Incubating
|
||||
public interface EntityHolder {
|
||||
EntityKey getEntityKey();
|
||||
EntityPersister getDescriptor();
|
||||
|
||||
/**
|
||||
* The entity object, or {@code null} if no entity object was registered yet.
|
||||
*/
|
||||
@Nullable Object getEntity();
|
||||
/**
|
||||
* The proxy object, or {@code null} if no proxy object was registered yet.
|
||||
*/
|
||||
@Nullable Object getProxy();
|
||||
/**
|
||||
* The entity initializer that claims to initialize the entity for this holder.
|
||||
* Will be {@code null} if entity is initialized already or the entity holder is not claimed yet.
|
||||
*/
|
||||
@Nullable EntityInitializer getEntityInitializer();
|
||||
|
||||
/**
|
||||
* The proxy if there is one and otherwise the entity.
|
||||
*/
|
||||
default @Nullable Object getManagedObject() {
|
||||
final Object proxy = getProxy();
|
||||
return proxy == null ? getEntity() : proxy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Marks the entity holder as reloaded to potentially trigger follow-on locking.
|
||||
*
|
||||
* @param processingState The processing state within which this entity is reloaded.
|
||||
*/
|
||||
void markAsReloaded(JdbcValuesSourceProcessingState processingState);
|
||||
|
||||
/**
|
||||
* Whether the entity is already initialized or will be initialized through an initializer eventually.
|
||||
*/
|
||||
boolean isEventuallyInitialized();
|
||||
}
|
||||
|
|
|
@ -10,9 +10,11 @@ import java.io.Serializable;
|
|||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.Internal;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.query.Query;
|
||||
|
@ -20,8 +22,12 @@ import org.hibernate.collection.spi.PersistentCollection;
|
|||
import org.hibernate.internal.util.MarkerObject;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||
import org.hibernate.sql.results.spi.LoadContexts;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
||||
/**
|
||||
* Represents the state of "stuff" Hibernate is tracking, including (not exhaustive):
|
||||
* <ul>
|
||||
|
@ -489,12 +495,31 @@ public interface PersistenceContext {
|
|||
// @Deprecated
|
||||
// HashSet getNullifiableEntityKeys();
|
||||
|
||||
/**
|
||||
* Return an existing entity holder for the entity key, possibly creating one if necessary.
|
||||
* Will claim the entity holder by registering the given entity initializer, if it isn't claimed yet.
|
||||
*
|
||||
* @param key The key under which to add an entity
|
||||
* @param entity The entity instance to add
|
||||
* @param processingState The processing state which initializes the entity if successfully claimed
|
||||
* @param initializer The initializer to claim the entity instance
|
||||
*/
|
||||
@Incubating
|
||||
EntityHolder claimEntityHolderIfPossible(
|
||||
EntityKey key,
|
||||
@Nullable Object entity,
|
||||
JdbcValuesSourceProcessingState processingState,
|
||||
EntityInitializer initializer);
|
||||
|
||||
EntityHolder getEntityHolder(EntityKey key);
|
||||
|
||||
boolean containsEntityHolder(EntityKey key);
|
||||
|
||||
EntityHolder removeEntityHolder(EntityKey key);
|
||||
|
||||
@Incubating
|
||||
void postLoad(JdbcValuesSourceProcessingState processingState, Consumer<EntityHolder> loadedConsumer);
|
||||
|
||||
/**
|
||||
* Doubly internal
|
||||
*/
|
||||
|
|
|
@ -12,13 +12,14 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.internal.util.NullnessUtil;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.select.QuerySpec;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcParametersList;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
|
||||
/**
|
||||
* Encapsulates details related to entities which contain sub-select-fetchable
|
||||
|
@ -118,12 +119,12 @@ public class SubselectFetch {
|
|||
}
|
||||
|
||||
public interface RegistrationHandler {
|
||||
void addKey(EntityKey key, LoadingEntityEntry entry);
|
||||
void addKey(EntityHolder holder);
|
||||
}
|
||||
|
||||
private static final RegistrationHandler NO_OP_REG_HANDLER = new RegistrationHandler() {
|
||||
@Override
|
||||
public void addKey(EntityKey key, LoadingEntityEntry entry) {
|
||||
public void addKey(EntityHolder holder) {
|
||||
}
|
||||
} ;
|
||||
|
||||
|
@ -146,23 +147,25 @@ public class SubselectFetch {
|
|||
this.loadingJdbcParameterBindings = loadingJdbcParameterBindings;
|
||||
}
|
||||
|
||||
public void addKey(EntityKey key, LoadingEntityEntry entry) {
|
||||
@Override
|
||||
public void addKey(EntityHolder holder) {
|
||||
if ( batchFetchQueue.getSession().getLoadQueryInfluencers()
|
||||
.hasSubselectLoadableCollections( entry.getDescriptor() ) ) {
|
||||
.hasSubselectLoadableCollections( holder.getDescriptor() ) ) {
|
||||
final EntityInitializer entityInitializer = NullnessUtil.castNonNull( holder.getEntityInitializer() );
|
||||
final SubselectFetch subselectFetch = subselectFetches.computeIfAbsent(
|
||||
entry.getEntityInitializer().getNavigablePath(),
|
||||
entityInitializer.getNavigablePath(),
|
||||
navigablePath -> new SubselectFetch(
|
||||
loadingSqlAst.getQuerySpec(),
|
||||
loadingSqlAst.getQuerySpec()
|
||||
.getFromClause()
|
||||
.findTableGroup( entry.getEntityInitializer().getNavigablePath() ),
|
||||
.findTableGroup( entityInitializer.getNavigablePath() ),
|
||||
loadingJdbcParameters,
|
||||
loadingJdbcParameterBindings,
|
||||
new HashSet<>()
|
||||
)
|
||||
);
|
||||
subselectFetch.resultingEntityKeys.add( key );
|
||||
batchFetchQueue.addSubselect( key, subselectFetch );
|
||||
subselectFetch.resultingEntityKeys.add( holder.getEntityKey() );
|
||||
batchFetchQueue.addSubselect( holder.getEntityKey(), subselectFetch );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -274,7 +274,8 @@ public class DefaultLoadEventListener implements LoadEventListener {
|
|||
private Object loadWithRegularProxy(LoadEvent event, EntityPersister persister, EntityKey keyToLoad, LoadType options) {
|
||||
// This is the case where the proxy is a separate object:
|
||||
// look for a proxy
|
||||
final EntityHolder holder = event.getSession().getPersistenceContextInternal().getEntityHolder( keyToLoad );
|
||||
final PersistenceContext persistenceContext = event.getSession().getPersistenceContextInternal();
|
||||
final EntityHolder holder = persistenceContext.getEntityHolder( keyToLoad );
|
||||
final Object proxy = holder == null ? null : holder.getProxy();
|
||||
if ( proxy != null ) {
|
||||
// narrow the existing proxy to the type we're looking for
|
||||
|
|
|
@ -347,7 +347,7 @@ public class FetchingScrollableResultsImpl<R> extends AbstractScrollableResults<
|
|||
}
|
||||
|
||||
}
|
||||
getJdbcValuesSourceProcessingState().finishUp();
|
||||
getJdbcValuesSourceProcessingState().finishUp( false );
|
||||
}
|
||||
finally {
|
||||
persistenceContext.afterLoad();
|
||||
|
|
|
@ -132,7 +132,7 @@ public class ScrollableResultsImpl<R> extends AbstractScrollableResults<R> {
|
|||
currentRow = getRowReader().readRow( getRowProcessingState(), getProcessingOptions() );
|
||||
|
||||
getRowProcessingState().finishRowProcessing();
|
||||
getJdbcValuesSourceProcessingState().finishUp();
|
||||
getJdbcValuesSourceProcessingState().finishUp( false );
|
||||
}
|
||||
finally {
|
||||
persistenceContext.afterLoad();
|
||||
|
|
|
@ -19,6 +19,7 @@ import org.hibernate.engine.internal.CacheHelper;
|
|||
import org.hibernate.engine.internal.StatefulPersistenceContext;
|
||||
import org.hibernate.engine.internal.TwoPhaseLoad;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptor;
|
||||
|
@ -398,9 +399,19 @@ public class CacheEntityLoaderHelper {
|
|||
subclassPersister = factory.getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.getEntityDescriptor( entry.getSubclass() );
|
||||
entity = instanceToLoad == null
|
||||
? source.instantiate( subclassPersister, entityId )
|
||||
: instanceToLoad;
|
||||
if ( instanceToLoad != null ) {
|
||||
entity = instanceToLoad;
|
||||
}
|
||||
else {
|
||||
final EntityHolder holder = source.getPersistenceContextInternal().getEntityHolder( entityKey );
|
||||
if ( holder != null && holder.getEntity() != null ) {
|
||||
// Use the entity which might already be
|
||||
entity = holder.getEntity();
|
||||
}
|
||||
else {
|
||||
entity = source.instantiate( subclassPersister, entityId );
|
||||
}
|
||||
}
|
||||
|
||||
if ( isPersistentAttributeInterceptable( entity ) ) {
|
||||
PersistentAttributeInterceptor persistentAttributeInterceptor = asPersistentAttributeInterceptable( entity ).$$_hibernate_getInterceptor();
|
||||
|
|
|
@ -10,7 +10,7 @@ import org.hibernate.LockOptions;
|
|||
import org.hibernate.collection.spi.PersistentCollection;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
@ -27,7 +27,6 @@ import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
|||
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcParametersList;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
|
||||
|
@ -148,8 +147,8 @@ public class CollectionLoaderSingleKey implements CollectionLoader {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchableKeysHandler.addKey( entityKey, entry );
|
||||
public void registerLoadingEntityHolder(EntityHolder holder) {
|
||||
subSelectFetchableKeysHandler.addKey( holder );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -6,11 +6,10 @@
|
|||
*/
|
||||
package org.hibernate.loader.ast.internal;
|
||||
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.sql.exec.internal.BaseExecutionContext;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
|
||||
class ExecutionContextWithSubselectFetchHandler extends BaseExecutionContext {
|
||||
|
||||
|
@ -24,9 +23,9 @@ class ExecutionContextWithSubselectFetchHandler extends BaseExecutionContext {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
public void registerLoadingEntityHolder(EntityHolder holder) {
|
||||
if ( subSelectFetchableKeysHandler != null ) {
|
||||
subSelectFetchableKeysHandler.addKey( entityKey, entry );
|
||||
subSelectFetchableKeysHandler.addKey( holder );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
package org.hibernate.loader.ast.internal;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryOptionsAdapter;
|
||||
import org.hibernate.sql.exec.internal.BaseExecutionContext;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -75,8 +74,8 @@ class SingleIdExecutionContext extends BaseExecutionContext {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchableKeysHandler.addKey( entityKey, entry );
|
||||
public void registerLoadingEntityHolder(EntityHolder holder) {
|
||||
subSelectFetchableKeysHandler.addKey( holder );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,7 +46,6 @@ import org.hibernate.sql.results.graph.FetchParent;
|
|||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.graph.embeddable.internal.NonAggregatedIdentifierMappingFetch;
|
||||
import org.hibernate.sql.results.graph.embeddable.internal.NonAggregatedIdentifierMappingResult;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
|
||||
/**
|
||||
* A "non-aggregated" composite identifier.
|
||||
|
@ -293,10 +292,8 @@ public class NonAggregatedIdentifierMappingImpl extends AbstractCompositeIdentif
|
|||
toOneAttributeMapping.getAttributeName()
|
||||
);
|
||||
if ( o == null ) {
|
||||
final LoadingEntityEntry loadingEntityEntry = persistenceContext.getLoadContexts()
|
||||
.findLoadingEntityEntry( entityKey );
|
||||
if ( loadingEntityEntry != null ) {
|
||||
o = loadingEntityEntry.getEntityInstance();
|
||||
if ( holder != null && holder.isEventuallyInitialized() ) {
|
||||
o = holder.getEntity();
|
||||
}
|
||||
else {
|
||||
o = session.internalLoad(
|
||||
|
|
|
@ -86,6 +86,7 @@ import org.hibernate.engine.spi.CascadeStyle;
|
|||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityEntryFactory;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.NaturalIdResolutions;
|
||||
|
@ -276,7 +277,6 @@ import org.hibernate.sql.results.graph.Fetch;
|
|||
import org.hibernate.sql.results.graph.FetchParent;
|
||||
import org.hibernate.sql.results.graph.Fetchable;
|
||||
import org.hibernate.sql.results.graph.FetchableContainer;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.graph.entity.internal.EntityResultImpl;
|
||||
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
|
@ -4112,14 +4112,15 @@ public abstract class AbstractEntityPersister
|
|||
final Object version = getVersion( entity );
|
||||
final Boolean isUnsaved = versionMapping.getUnsavedStrategy().isUnsaved( version );
|
||||
if ( isUnsaved != null ) {
|
||||
if ( isUnsaved ) {
|
||||
if ( version == null && session.getPersistenceContext().hasLoadContext() ) {
|
||||
if ( isUnsaved ) {
|
||||
final PersistenceContext persistenceContext;
|
||||
if ( version == null && ( persistenceContext = session.getPersistenceContext() ).hasLoadContext()
|
||||
&& !persistenceContext.getLoadContexts().isLoadingFinished() ) {
|
||||
// check if we're currently loading this entity instance, the version
|
||||
// will be null but the entity cannot be considered transient
|
||||
final LoadingEntityEntry loadingEntityEntry = session.getPersistenceContext()
|
||||
.getLoadContexts()
|
||||
.findLoadingEntityEntry( new EntityKey( id, this ) );
|
||||
if ( loadingEntityEntry != null && loadingEntityEntry.getEntityInstance() == entity ) {
|
||||
final EntityHolder holder = persistenceContext
|
||||
.getEntityHolder( new EntityKey( id, this ) );
|
||||
if ( holder != null && holder.isEventuallyInitialized() && holder.getEntity() == entity ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ import jakarta.persistence.Tuple;
|
|||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.InstantiationException;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
|
@ -42,7 +42,6 @@ import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
|||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.exec.spi.JdbcParametersList;
|
||||
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.internal.RowTransformerArrayImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerConstructorImpl;
|
||||
import org.hibernate.sql.results.internal.RowTransformerJpaTupleImpl;
|
||||
|
@ -497,8 +496,8 @@ public class ConcreteSqmSelectQueryPlan<R> implements SelectQueryPlan<R> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
subSelectFetchKeyHandler.addKey( entityKey, entry );
|
||||
public void registerLoadingEntityHolder(EntityHolder holder) {
|
||||
subSelectFetchKeyHandler.addKey( holder );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -221,6 +221,7 @@ public class OutputsImpl implements Outputs {
|
|||
executionContext,
|
||||
processingOptions
|
||||
);
|
||||
final ArrayList<Object> results = new ArrayList<>();
|
||||
try {
|
||||
final RowProcessingStateStandardImpl rowProcessingState = new RowProcessingStateStandardImpl(
|
||||
jdbcValuesSourceProcessingState,
|
||||
|
@ -229,8 +230,6 @@ public class OutputsImpl implements Outputs {
|
|||
jdbcValues
|
||||
);
|
||||
|
||||
|
||||
final ArrayList<Object> results = new ArrayList<>();
|
||||
while ( rowProcessingState.next() ) {
|
||||
results.add( rowReader.readRow( rowProcessingState, processingOptions ) );
|
||||
rowProcessingState.finishRowProcessing();
|
||||
|
@ -248,7 +247,7 @@ public class OutputsImpl implements Outputs {
|
|||
}
|
||||
finally {
|
||||
rowReader.finishUp( jdbcValuesSourceProcessingState );
|
||||
jdbcValuesSourceProcessingState.finishUp();
|
||||
jdbcValuesSourceProcessingState.finishUp( results.size() > 1 );
|
||||
jdbcValues.finishUp( this.context.getSession() );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,14 +7,13 @@
|
|||
package org.hibernate.sql.exec.spi;
|
||||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.query.spi.QueryParameterBindings;
|
||||
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
|
||||
/**
|
||||
* A context for execution of SQL statements expressed via
|
||||
|
@ -65,18 +64,10 @@ public interface ExecutionContext {
|
|||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #registerSubselect(EntityKey, LoadingEntityEntry)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
default void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
default void registerLoadingEntityHolder(EntityHolder holder) {
|
||||
// by default do nothing
|
||||
}
|
||||
|
||||
default void registerSubselect(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
registerLoadingEntityEntry( entityKey, entry );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook to allow delaying calls to {@link LogicalConnectionImplementor#afterStatement()}.
|
||||
* Mainly used in the case of batching and multi-table mutations
|
||||
|
|
|
@ -6,9 +6,9 @@
|
|||
*/
|
||||
package org.hibernate.sql.exec.spi;
|
||||
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
|
@ -21,19 +21,9 @@ public class StandardEntityInstanceResolver {
|
|||
EntityKey entityKey,
|
||||
boolean eager,
|
||||
SharedSessionContractImplementor session) {
|
||||
// First, look for it in the PC as a managed entity
|
||||
final Object managedEntity = session.getPersistenceContext().getEntity( entityKey );
|
||||
if ( managedEntity != null ) {
|
||||
// todo (6.0) : check status? aka, return deleted entities?
|
||||
return managedEntity;
|
||||
}
|
||||
|
||||
// Next, check currently loading entities
|
||||
final LoadingEntityEntry loadingEntry = session.getPersistenceContext()
|
||||
.getLoadContexts()
|
||||
.findLoadingEntityEntry( entityKey );
|
||||
if ( loadingEntry != null ) {
|
||||
return loadingEntry.getEntityInstance();
|
||||
final EntityHolder holder = session.getPersistenceContext().getEntityHolder( entityKey );
|
||||
if ( holder != null && holder.isEventuallyInitialized() ) {
|
||||
return holder.getEntity();
|
||||
}
|
||||
|
||||
// Lastly, try to load from database
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.sql.results.graph.embeddable.internal;
|
||||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
|
@ -18,7 +19,6 @@ import org.hibernate.sql.exec.internal.BaseExecutionContext;
|
|||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.graph.entity.EntityFetch;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
import org.hibernate.sql.results.spi.RowReader;
|
||||
|
@ -131,8 +131,8 @@ public class NestedRowProcessingState extends BaseExecutionContext implements Ro
|
|||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
processingState.registerLoadingEntityEntry( entityKey, entry );
|
||||
public void registerLoadingEntityHolder(EntityHolder holder) {
|
||||
processingState.registerLoadingEntityHolder( holder );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -388,17 +388,19 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
missing = true;
|
||||
return;
|
||||
}
|
||||
// Special case map proxy to avoid stack overflows
|
||||
// We know that a map proxy will always be of "the right type" so just use that object
|
||||
final LoadingEntityEntry existingLoadingEntry =
|
||||
rowProcessingState.getSession().getPersistenceContextInternal().getLoadContexts()
|
||||
.findLoadingEntityEntry( entityKey );
|
||||
setIsOwningInitializer( entityKey.getIdentifier(), existingLoadingEntry );
|
||||
|
||||
final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContextInternal();
|
||||
final EntityHolder holder = persistenceContext.claimEntityHolderIfPossible(
|
||||
entityKey,
|
||||
null,
|
||||
rowProcessingState.getJdbcValuesSourceProcessingState(),
|
||||
this
|
||||
);
|
||||
isOwningInitializer = holder.getEntityInitializer() == this;
|
||||
if ( entityInstance == null ) {
|
||||
resolveEntityInstance( rowProcessingState, existingLoadingEntry, entityKey.getIdentifier() );
|
||||
resolveEntityInstance( rowProcessingState, holder, entityKey.getIdentifier() );
|
||||
}
|
||||
else if ( existingLoadingEntry != null && existingLoadingEntry.getEntityInitializer() != this ) {
|
||||
else if ( !isOwningInitializer ) {
|
||||
entityInstance = holder.getManagedObject();
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
|
@ -486,7 +488,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
|
||||
protected void resolveEntityInstance(
|
||||
RowProcessingState rowProcessingState,
|
||||
LoadingEntityEntry existingLoadingEntry,
|
||||
EntityHolder holder,
|
||||
Object entityIdentifier) {
|
||||
|
||||
if ( EntityLoadingLogging.ENTITY_LOADING_LOGGER.isTraceEnabled() ) {
|
||||
|
@ -498,30 +500,34 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
);
|
||||
}
|
||||
|
||||
final PersistenceContext persistenceContext = rowProcessingState.getSession().getPersistenceContextInternal();
|
||||
final EntityHolder holder = persistenceContext.getEntityHolder( entityKey );
|
||||
final Object proxy = holder == null ? null : holder.getProxy();
|
||||
final Object proxy = holder.getProxy();
|
||||
final boolean unwrapProxy = proxy != null && referencedModelPart instanceof ToOneAttributeMapping
|
||||
&& ( (ToOneAttributeMapping) referencedModelPart ).isUnwrapProxy()
|
||||
&& getConcreteDescriptor().getBytecodeEnhancementMetadata().isEnhancedForLazyLoading();
|
||||
final Object entityInstanceFromExecutionContext = getEntityInstanceFromExecutionContext( rowProcessingState );
|
||||
final Object entityFromExecutionContext;
|
||||
if ( !unwrapProxy && isProxyInstance( proxy ) ) {
|
||||
if ( entityInstanceFromExecutionContext != null ) {
|
||||
entityInstance = entityInstanceFromExecutionContext;
|
||||
registerLoadingEntityInstanceFromExecutionContext( rowProcessingState, entityInstance );
|
||||
if ( ( entityFromExecutionContext = getEntityFromExecutionContext( rowProcessingState ) ) != null ) {
|
||||
entityInstance = entityFromExecutionContext;
|
||||
// If the entity comes from the execution context, it is treated as not initialized
|
||||
// so that we can refresh the data as requested
|
||||
registerReloadedEntity( rowProcessingState, holder );
|
||||
}
|
||||
else {
|
||||
entityInstance = proxy;
|
||||
if ( Hibernate.isInitialized( entityInstance ) ) {
|
||||
this.isInitialized = true;
|
||||
registerReloadedEntity( rowProcessingState, holder );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
final Object existingEntity = holder == null ? null : holder.getEntity();
|
||||
final Object existingEntity = holder.getEntity();
|
||||
if ( existingEntity != null ) {
|
||||
entityInstance = existingEntity;
|
||||
if ( existingLoadingEntry == null ) {
|
||||
if ( holder.getEntityInitializer() == null ) {
|
||||
if ( isExistingEntityInitialized( existingEntity ) ) {
|
||||
this.isInitialized = true;
|
||||
registerReloadedEntity( rowProcessingState, existingEntity );
|
||||
registerReloadedEntity( rowProcessingState, holder );
|
||||
notifyResolutionListeners( entityInstance );
|
||||
if ( rowProcessingState.getQueryOptions().isResultCachingEnabled() == Boolean.TRUE ) {
|
||||
// We still need to read result set values to correctly populate the query cache
|
||||
|
@ -532,15 +538,18 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
registerLoadingEntityInstanceFromExecutionContext( rowProcessingState, entityInstance );
|
||||
}
|
||||
}
|
||||
else if ( !isOwningInitializer ) {
|
||||
this.isInitialized = true;
|
||||
}
|
||||
}
|
||||
else if ( entityInstanceFromExecutionContext != null ) {
|
||||
entityInstance = entityInstanceFromExecutionContext;
|
||||
else if ( ( entityFromExecutionContext = getEntityFromExecutionContext( rowProcessingState ) ) != null ) {
|
||||
entityInstance = entityFromExecutionContext;
|
||||
registerLoadingEntityInstanceFromExecutionContext( rowProcessingState, entityInstance );
|
||||
}
|
||||
else {
|
||||
// look to see if another initializer from a parent load context or an earlier
|
||||
// initializer is already loading the entity
|
||||
entityInstance = resolveInstance( entityIdentifier, existingLoadingEntry, rowProcessingState );
|
||||
entityInstance = resolveInstance( entityIdentifier, holder, rowProcessingState );
|
||||
if ( isOwningInitializer && !isInitialized && identifierAssembler instanceof EmbeddableAssembler ) {
|
||||
// If this is the owning initializer and the returned object is not initialized,
|
||||
// this means that the entity instance was just instantiated.
|
||||
|
@ -549,16 +558,15 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
identifierAssembler.assemble( rowProcessingState );
|
||||
}
|
||||
}
|
||||
|
||||
upgradeLockMode( rowProcessingState );
|
||||
}
|
||||
upgradeLockMode( rowProcessingState );
|
||||
}
|
||||
|
||||
protected abstract void registerLoadingEntityInstanceFromExecutionContext(
|
||||
RowProcessingState rowProcessingState,
|
||||
Object instance);
|
||||
|
||||
protected Object getEntityInstanceFromExecutionContext(RowProcessingState rowProcessingState) {
|
||||
protected Object getEntityFromExecutionContext(RowProcessingState rowProcessingState) {
|
||||
final ExecutionContext executionContext = rowProcessingState.getJdbcValuesSourceProcessingState()
|
||||
.getExecutionContext();
|
||||
if ( rootEntityDescriptor == executionContext.getRootEntityDescriptor()
|
||||
|
@ -614,37 +622,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
|
||||
}
|
||||
|
||||
private void setIsOwningInitializer(Object entityIdentifier,LoadingEntityEntry existingLoadingEntry) {
|
||||
if ( existingLoadingEntry != null ) {
|
||||
if ( EntityLoadingLogging.ENTITY_LOADING_LOGGER.isDebugEnabled() ) {
|
||||
EntityLoadingLogging.ENTITY_LOADING_LOGGER.debugf(
|
||||
"(%s) Found existing loading entry [%s] - using loading instance",
|
||||
getSimpleConcreteImplName(),
|
||||
toLoggableString( getNavigablePath(), entityIdentifier )
|
||||
);
|
||||
}
|
||||
if ( existingLoadingEntry.getEntityInitializer() == this ) {
|
||||
isOwningInitializer = true;
|
||||
}
|
||||
else {
|
||||
isInitialized = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
isOwningInitializer = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isOwningInitializer() {
|
||||
return isOwningInitializer;
|
||||
}
|
||||
|
||||
private Object resolveInstance(
|
||||
Object entityIdentifier,
|
||||
LoadingEntityEntry existingLoadingEntry,
|
||||
EntityHolder holder,
|
||||
RowProcessingState rowProcessingState) {
|
||||
if ( isOwningInitializer ) {
|
||||
assert existingLoadingEntry == null || existingLoadingEntry.getEntityInstance() == null;
|
||||
assert holder.getEntity() == null;
|
||||
return resolveEntityInstance( entityIdentifier, rowProcessingState );
|
||||
}
|
||||
else {
|
||||
|
@ -654,10 +637,10 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
"(%s) Entity [%s] being loaded by another initializer [%s] - skipping processing",
|
||||
getSimpleConcreteImplName(),
|
||||
toLoggableString( getNavigablePath(), entityIdentifier ),
|
||||
existingLoadingEntry.getEntityInitializer()
|
||||
holder.getEntityInitializer()
|
||||
);
|
||||
}
|
||||
return existingLoadingEntry.getEntityInstance();
|
||||
return holder.getEntity();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -675,7 +658,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
// EARLY EXIT!!!
|
||||
// because the second level cache has reference cache entries, the entity is initialized
|
||||
isInitialized = true;
|
||||
registerReloadedEntity( rowProcessingState, cached );
|
||||
registerReloadedEntity( rowProcessingState );
|
||||
return cached;
|
||||
}
|
||||
}
|
||||
|
@ -729,21 +712,25 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
}
|
||||
|
||||
protected void registerLoadingEntity(RowProcessingState rowProcessingState, Object instance) {
|
||||
rowProcessingState.getJdbcValuesSourceProcessingState()
|
||||
.registerLoadingEntity(
|
||||
entityKey,
|
||||
new LoadingEntityEntry( this, entityKey, concreteDescriptor, instance )
|
||||
);
|
||||
rowProcessingState.getSession().getPersistenceContextInternal().claimEntityHolderIfPossible(
|
||||
entityKey,
|
||||
instance,
|
||||
rowProcessingState.getJdbcValuesSourceProcessingState(),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
protected void registerReloadedEntity(RowProcessingState rowProcessingState, Object instance) {
|
||||
protected void registerReloadedEntity(RowProcessingState rowProcessingState) {
|
||||
if ( rowProcessingState.hasCallbackActions() ) {
|
||||
rowProcessingState.getSession().getPersistenceContextInternal().getEntityHolder( entityKey )
|
||||
.markAsReloaded( rowProcessingState.getJdbcValuesSourceProcessingState() );
|
||||
}
|
||||
}
|
||||
|
||||
protected void registerReloadedEntity(RowProcessingState rowProcessingState, EntityHolder holder) {
|
||||
if ( rowProcessingState.hasCallbackActions() ) {
|
||||
// This is only needed for follow-on locking, so skip registering the entity if there is no callback
|
||||
rowProcessingState.getJdbcValuesSourceProcessingState()
|
||||
.registerReloadedEntity(
|
||||
entityKey,
|
||||
new LoadingEntityEntry( this, entityKey, concreteDescriptor, instance )
|
||||
);
|
||||
holder.markAsReloaded( rowProcessingState.getJdbcValuesSourceProcessingState() );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -754,11 +741,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
final SharedSessionContractImplementor session = rowProcessingState.getSession();
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
if ( lazyInitializer != null ) {
|
||||
Object instance = persistenceContext.getEntity( entityKey );
|
||||
final EntityHolder holder = persistenceContext.getEntityHolder( entityKey );
|
||||
Object instance = holder.getEntity();
|
||||
if ( instance == null ) {
|
||||
instance = resolveInstance(
|
||||
entityKey.getIdentifier(),
|
||||
persistenceContext.getLoadContexts().findLoadingEntityEntry( entityKey ),
|
||||
holder,
|
||||
rowProcessingState
|
||||
);
|
||||
initializeEntity( instance, rowProcessingState );
|
||||
|
@ -788,15 +776,8 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
then when the EntitySelectFetchInitializer#initializeInstance() is executed before the EntityResultInitializer one
|
||||
the persistence context will contain the instances retrieved form the 2LC
|
||||
*/
|
||||
final Object entity = persistenceContext.getEntity( entityKey );
|
||||
if ( entity != null ) {
|
||||
entityInstance = entity;
|
||||
registerLoadingEntity( rowProcessingState, entityInstance );
|
||||
initializeEntityInstance( entityInstance, rowProcessingState );
|
||||
}
|
||||
else {
|
||||
initializeEntity( entityInstance, rowProcessingState );
|
||||
}
|
||||
assert persistenceContext.getEntityHolder( entityKey ).getEntityInitializer() == this;
|
||||
initializeEntity( entityInstance, rowProcessingState );
|
||||
entityInstanceForNotify = entityInstance;
|
||||
}
|
||||
else {
|
||||
|
@ -1100,8 +1081,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
|
|||
if ( entry.getStatus() != Status.LOADING ) {
|
||||
// If the instance to initialize is the main entity, we can't skip this.
|
||||
// This can happen if we initialize an enhanced proxy.
|
||||
return !isEntityReturn()
|
||||
|| rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions()
|
||||
return rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions()
|
||||
.getEffectiveOptionalObject() != toInitialize;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -15,7 +15,9 @@ import org.hibernate.persister.entity.EntityPersister;
|
|||
* Representation of an entity being loaded, containing its state
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
* @deprecated Now modeled through {@link org.hibernate.engine.spi.EntityHolder}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
public class LoadingEntityEntry {
|
||||
private final EntityInitializer entityInitializer;
|
||||
private final EntityKey entityKey;
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.sql.results.graph.entity.internal;
|
|||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.PersistentAttributeInterceptable;
|
||||
|
@ -23,7 +24,6 @@ import org.hibernate.sql.results.graph.AbstractFetchParentAccess;
|
|||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
|
||||
import static org.hibernate.engine.internal.ManagedTypeHelper.asPersistentAttributeInterceptableOrNull;
|
||||
|
@ -105,24 +105,9 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
|
|||
assert entityKey != null;
|
||||
final SharedSessionContractImplementor session = rowProcessingState.getSession();
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
final Object instance = persistenceContext.getEntity( entityKey );
|
||||
if ( instance == null ) {
|
||||
final LoadingEntityEntry loadingEntityEntry = persistenceContext
|
||||
.getLoadContexts().findLoadingEntityEntry( entityKey );
|
||||
if ( loadingEntityEntry != null ) {
|
||||
return loadingEntityEntry.getEntityInstance();
|
||||
}
|
||||
}
|
||||
else if ( isInitialized( instance ) ) {
|
||||
return instance;
|
||||
}
|
||||
else {
|
||||
// the instance is not initialized but there is another initialzier that is loading it
|
||||
final LoadingEntityEntry loadingEntityEntry = persistenceContext
|
||||
.getLoadContexts().findLoadingEntityEntry( entityKey );
|
||||
if ( loadingEntityEntry != null ) {
|
||||
return loadingEntityEntry.getEntityInstance();
|
||||
}
|
||||
final EntityHolder holder = persistenceContext.getEntityHolder( entityKey );
|
||||
if ( holder != null && holder.getEntity() != null && holder.isEventuallyInitialized() ) {
|
||||
return holder.getEntity();
|
||||
}
|
||||
// we need to register a resolution listener only if there is not an already initialized instance
|
||||
// or an instance that another initialzier is loading
|
||||
|
|
|
@ -13,6 +13,7 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
@ -129,7 +130,8 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
|
|||
final Object loadedInstance = loadInstance( entityKey, referencedModelPart, session );
|
||||
for ( ParentInfo parentInfo : parentInfos ) {
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
final Object entity = persistenceContext.getEntity( parentInfo.initializerEntityKey );
|
||||
final EntityHolder holder = persistenceContext.getEntityHolder( parentInfo.initializerEntityKey );
|
||||
final Object entity = holder.getEntity();
|
||||
setInstance(
|
||||
firstEntityInitializer,
|
||||
referencedModelPart,
|
||||
|
|
|
@ -25,7 +25,6 @@ import org.hibernate.sql.results.graph.AbstractFetchParentAccess;
|
|||
import org.hibernate.sql.results.graph.DomainResultAssembler;
|
||||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
|
@ -102,16 +101,9 @@ public class EntityDelayedFetchInitializer extends AbstractFetchParentAccess imp
|
|||
final EntityKey entityKey = new EntityKey( identifier, concreteDescriptor );
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
|
||||
final LoadingEntityEntry loadingEntityLocally = persistenceContext.getLoadContexts()
|
||||
.findLoadingEntityEntry( entityKey );
|
||||
if ( loadingEntityLocally != null ) {
|
||||
entityInstance = loadingEntityLocally.getEntityInstance();
|
||||
}
|
||||
if ( entityInstance == null ) {
|
||||
final EntityHolder holder = persistenceContext.getEntityHolder( entityKey );
|
||||
if ( holder != null && holder.getEntity() != null ) {
|
||||
entityInstance = persistenceContext.proxyFor( holder );
|
||||
}
|
||||
final EntityHolder holder = persistenceContext.getEntityHolder( entityKey );
|
||||
if ( holder != null && holder.getEntity() != null ) {
|
||||
entityInstance = persistenceContext.proxyFor( holder );
|
||||
}
|
||||
}
|
||||
if ( entityInstance == null ) {
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.function.Consumer;
|
|||
import org.hibernate.FetchNotFoundException;
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.annotations.NotFoundAction;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
@ -29,9 +30,7 @@ import org.hibernate.sql.results.graph.DomainResultAssembler;
|
|||
import org.hibernate.sql.results.graph.FetchParentAccess;
|
||||
import org.hibernate.sql.results.graph.entity.EntityInitializer;
|
||||
import org.hibernate.sql.results.graph.entity.EntityLoadingLogging;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
|
||||
import org.hibernate.sql.results.spi.LoadContexts;
|
||||
|
||||
import static org.hibernate.internal.log.LoggingHelper.toLoggableString;
|
||||
|
||||
|
@ -140,16 +139,8 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
|
|||
final EntityKey entityKey = new EntityKey( entityIdentifier, concreteDescriptor );
|
||||
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
entityInstance = persistenceContext.getEntity( entityKey );
|
||||
if ( entityInstance != null && Hibernate.isInitialized( entityInstance )) {
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
|
||||
final LoadContexts loadContexts = session.getPersistenceContext().getLoadContexts();
|
||||
final LoadingEntityEntry existingLoadingEntry = loadContexts.findLoadingEntityEntry( entityKey );
|
||||
|
||||
if ( existingLoadingEntry != null ) {
|
||||
final EntityHolder holder = persistenceContext.getEntityHolder( entityKey );
|
||||
if ( holder != null ) {
|
||||
if ( EntityLoadingLogging.ENTITY_LOADING_LOGGER.isDebugEnabled() ) {
|
||||
EntityLoadingLogging.ENTITY_LOADING_LOGGER.debugf(
|
||||
"(%s) Found existing loading entry [%s] - using loading instance",
|
||||
|
@ -160,29 +151,29 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
|
|||
)
|
||||
);
|
||||
}
|
||||
this.entityInstance = existingLoadingEntry.getEntityInstance();
|
||||
|
||||
final EntityInitializer entityInitializer = existingLoadingEntry.getEntityInitializer();
|
||||
if ( entityInitializer != this ) {
|
||||
entityInstance = holder.getEntity();
|
||||
if ( holder.getEntityInitializer() == null ) {
|
||||
if ( entityInstance != null && Hibernate.isInitialized( entityInstance ) ) {
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if ( holder.getEntityInitializer() != this ) {
|
||||
// the entity is already being loaded elsewhere
|
||||
if ( EntityLoadingLogging.ENTITY_LOADING_LOGGER.isDebugEnabled() ) {
|
||||
EntityLoadingLogging.ENTITY_LOADING_LOGGER.debugf(
|
||||
"(%s) Entity [%s] being loaded by another initializer [%s] - skipping processing",
|
||||
CONCRETE_NAME,
|
||||
toLoggableString( getNavigablePath(), entityIdentifier ),
|
||||
entityInitializer
|
||||
holder.getEntityInitializer()
|
||||
);
|
||||
}
|
||||
|
||||
// EARLY EXIT!!!
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
if ( entityInstance == null ) {
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
else if ( entityInstance == null ) {
|
||||
isInitialized = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -205,11 +196,12 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
|
|||
if ( toOneMapping.getNotFoundAction() == NotFoundAction.EXCEPTION ) {
|
||||
throw new FetchNotFoundException( entityName, entityIdentifier );
|
||||
}
|
||||
rowProcessingState.getJdbcValuesSourceProcessingState()
|
||||
.registerLoadingEntity(
|
||||
entityKey,
|
||||
new LoadingEntityEntry( this, entityKey, concreteDescriptor, entityInstance )
|
||||
);
|
||||
rowProcessingState.getSession().getPersistenceContextInternal().claimEntityHolderIfPossible(
|
||||
entityKey,
|
||||
entityInstance,
|
||||
rowProcessingState.getJdbcValuesSourceProcessingState(),
|
||||
this
|
||||
);
|
||||
}
|
||||
|
||||
if ( EntityLoadingLogging.ENTITY_LOADING_LOGGER.isDebugEnabled() ) {
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.sql.results.internal;
|
||||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.resource.jdbc.spi.LogicalConnectionImplementor;
|
||||
|
@ -18,7 +19,6 @@ import org.hibernate.sql.exec.spi.Callback;
|
|||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.graph.entity.EntityFetch;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesCacheHit;
|
||||
import org.hibernate.sql.results.jdbc.internal.JdbcValuesSourceProcessingStateStandardImpl;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValues;
|
||||
|
@ -179,8 +179,8 @@ public class RowProcessingStateStandardImpl extends BaseExecutionContext impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntityEntry(EntityKey entityKey, LoadingEntityEntry entry) {
|
||||
executionContext.registerLoadingEntityEntry( entityKey, entry );
|
||||
public void registerLoadingEntityHolder(EntityHolder holder) {
|
||||
executionContext.registerLoadingEntityHolder( holder );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -111,7 +111,6 @@ public class StandardRowReader<T> implements RowReader<T> {
|
|||
|
||||
@Override
|
||||
public void finishUp(JdbcValuesSourceProcessingState processingState) {
|
||||
processingState.registerSubselect();
|
||||
initializers.endLoading( processingState.getExecutionContext() );
|
||||
}
|
||||
|
||||
|
|
|
@ -10,26 +10,23 @@ import java.util.ArrayList;
|
|||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityHolder;
|
||||
import org.hibernate.engine.spi.EntityUniqueKey;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.event.service.spi.EventListenerGroup;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.event.spi.PostLoadEvent;
|
||||
import org.hibernate.event.spi.PostLoadEventListener;
|
||||
import org.hibernate.event.spi.PreLoadEvent;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.sql.exec.spi.Callback;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.graph.collection.CollectionInitializer;
|
||||
import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry;
|
||||
import org.hibernate.sql.results.graph.collection.internal.ArrayInitializer;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||
|
||||
|
@ -43,8 +40,6 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
private final ExecutionContext executionContext;
|
||||
private final JdbcValuesSourceProcessingOptions processingOptions;
|
||||
|
||||
private Map<EntityKey, LoadingEntityEntry> loadingEntityMap;
|
||||
private Map<EntityKey, LoadingEntityEntry> reloadedEntityMap;
|
||||
private Map<EntityUniqueKey, Initializer> initializerByUniquKeyMap;
|
||||
private Map<CollectionKey, LoadingCollectionEntry> loadingCollectionMap;
|
||||
private List<CollectionInitializer> arrayInitializers;
|
||||
|
@ -94,25 +89,6 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
return postLoadEvent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingEntity(
|
||||
EntityKey entityKey,
|
||||
LoadingEntityEntry loadingEntry) {
|
||||
if ( loadingEntityMap == null ) {
|
||||
loadingEntityMap = new HashMap<>();
|
||||
}
|
||||
loadingEntityMap.put( entityKey, loadingEntry );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerReloadedEntity(EntityKey entityKey, LoadingEntityEntry loadingEntry) {
|
||||
if ( reloadedEntityMap == null ) {
|
||||
reloadedEntityMap = new HashMap<>();
|
||||
}
|
||||
|
||||
reloadedEntityMap.put( entityKey, loadingEntry );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerInitializer(EntityUniqueKey entityKey, Initializer initializer) {
|
||||
if ( initializerByUniquKeyMap == null ) {
|
||||
|
@ -126,11 +102,6 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
return initializerByUniquKeyMap == null ? null : initializerByUniquKeyMap.get( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadingEntityEntry findLoadingEntityLocally(EntityKey entityKey) {
|
||||
return loadingEntityMap == null ? null : loadingEntityMap.get( entityKey );
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoadingCollectionEntry findLoadingCollectionLocally(CollectionKey key) {
|
||||
if ( loadingCollectionMap == null ) {
|
||||
|
@ -140,22 +111,6 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
return loadingCollectionMap.get( key );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSubselect() {
|
||||
if ( loadingEntityMap != null && loadingEntityMap.size() > 1 ) {
|
||||
loadingEntityMap.forEach(
|
||||
(entityKey, loadingEntityEntry) ->
|
||||
executionContext.registerSubselect( entityKey, loadingEntityEntry )
|
||||
);
|
||||
}
|
||||
else {
|
||||
LOG.tracef(
|
||||
"Skipping create subselects because there are fewer than 2 results, so query by key is more efficient.",
|
||||
getClass().getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerLoadingCollection(CollectionKey key, LoadingCollectionEntry loadingCollectionEntry) {
|
||||
if ( loadingCollectionMap == null ) {
|
||||
|
@ -177,61 +132,18 @@ public class JdbcValuesSourceProcessingStateStandardImpl implements JdbcValuesSo
|
|||
}
|
||||
|
||||
@Override
|
||||
public void finishUp() {
|
||||
public void finishUp(boolean registerSubselects) {
|
||||
// now we can finalize loading collections
|
||||
finishLoadingCollections();
|
||||
|
||||
postLoad();
|
||||
}
|
||||
|
||||
private void postLoad() {
|
||||
final Callback callback = executionContext.getCallback();
|
||||
if ( loadingEntityMap != null ) {
|
||||
final EventListenerGroup<PostLoadEventListener> listenerGroup = executionContext.getSession().getFactory()
|
||||
.getFastSessionServices()
|
||||
.eventListenerGroup_POST_LOAD;
|
||||
|
||||
loadingEntityMap.forEach(
|
||||
(entityKey, loadingEntityEntry) -> {
|
||||
if ( loadingEntityEntry.getEntityInstance() != null ) {
|
||||
if ( postLoadEvent != null ) {
|
||||
postLoadEvent.reset();
|
||||
postLoadEvent.setEntity( loadingEntityEntry.getEntityInstance() )
|
||||
.setId( entityKey.getIdentifier() )
|
||||
.setPersister( loadingEntityEntry.getDescriptor() );
|
||||
listenerGroup.fireEventOnEachListener(
|
||||
postLoadEvent,
|
||||
PostLoadEventListener::onPostLoad
|
||||
);
|
||||
}
|
||||
|
||||
if ( callback != null ) {
|
||||
callback.invokeAfterLoadActions(
|
||||
loadingEntityEntry.getEntityInstance(),
|
||||
loadingEntityEntry.getDescriptor(),
|
||||
getSession()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
final Consumer<EntityHolder> holderConsumer;
|
||||
if ( registerSubselects ) {
|
||||
holderConsumer = executionContext::registerLoadingEntityHolder;
|
||||
}
|
||||
loadingEntityMap = null;
|
||||
|
||||
if ( reloadedEntityMap != null ) {
|
||||
if ( callback != null ) {
|
||||
reloadedEntityMap.forEach(
|
||||
(entityKey, loadingEntityEntry) -> {
|
||||
callback.invokeAfterLoadActions(
|
||||
loadingEntityEntry.getEntityInstance(),
|
||||
loadingEntityEntry.getDescriptor(),
|
||||
getSession()
|
||||
);
|
||||
}
|
||||
);
|
||||
}
|
||||
reloadedEntityMap = null;
|
||||
else {
|
||||
holderConsumer = null;
|
||||
}
|
||||
executionContext.getSession().getPersistenceContextInternal().postLoad( this, holderConsumer );
|
||||
}
|
||||
|
||||
@SuppressWarnings("SimplifiableIfStatement")
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.sql.results.jdbc.spi;
|
||||
|
||||
import org.hibernate.engine.spi.CollectionKey;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.EntityUniqueKey;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.event.spi.PostLoadEvent;
|
||||
|
@ -15,7 +14,6 @@ import org.hibernate.event.spi.PreLoadEvent;
|
|||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.spi.LoadContexts;
|
||||
import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.sql.exec.spi.ExecutionContext;
|
||||
|
||||
|
@ -41,24 +39,6 @@ public interface JdbcValuesSourceProcessingState {
|
|||
PreLoadEvent getPreLoadEvent();
|
||||
PostLoadEvent getPostLoadEvent();
|
||||
|
||||
/**
|
||||
* Find a LoadingEntityEntry locally to this context.
|
||||
*
|
||||
* @see LoadContexts#findLoadingEntityEntry(EntityKey)
|
||||
*/
|
||||
LoadingEntityEntry findLoadingEntityLocally(EntityKey entityKey);
|
||||
|
||||
/**
|
||||
* Registers a LoadingEntityEntry locally to this context
|
||||
*/
|
||||
void registerLoadingEntity(
|
||||
EntityKey entityKey,
|
||||
LoadingEntityEntry loadingEntry);
|
||||
|
||||
void registerReloadedEntity(
|
||||
EntityKey entityKey,
|
||||
LoadingEntityEntry loadingEntry);
|
||||
|
||||
void registerInitializer(
|
||||
EntityUniqueKey entityKey,
|
||||
Initializer initializer);
|
||||
|
@ -80,8 +60,5 @@ public interface JdbcValuesSourceProcessingState {
|
|||
CollectionKey collectionKey,
|
||||
LoadingCollectionEntry loadingCollectionEntry);
|
||||
|
||||
default void registerSubselect() {
|
||||
}
|
||||
|
||||
void finishUp();
|
||||
void finishUp(boolean registerSubselects);
|
||||
}
|
||||
|
|
|
@ -174,12 +174,14 @@ public class ListResultsConsumer<R> implements ResultsConsumer<List<R>, R> {
|
|||
results = new Results<>( domainResultJavaType );
|
||||
}
|
||||
|
||||
int readRows = 0;
|
||||
if ( uniqueSemantic == UniqueSemantic.FILTER
|
||||
|| uniqueSemantic == UniqueSemantic.ASSERT && rowProcessingState.hasCollectionInitializers()
|
||||
|| uniqueSemantic == UniqueSemantic.ALLOW && isEntityResultType ) {
|
||||
while ( rowProcessingState.next() ) {
|
||||
results.addUnique( rowReader.readRow( rowProcessingState, processingOptions ) );
|
||||
rowProcessingState.finishRowProcessing();
|
||||
readRows++;
|
||||
}
|
||||
}
|
||||
else if ( uniqueSemantic == UniqueSemantic.ASSERT ) {
|
||||
|
@ -194,18 +196,20 @@ public class ListResultsConsumer<R> implements ResultsConsumer<List<R>, R> {
|
|||
);
|
||||
}
|
||||
rowProcessingState.finishRowProcessing();
|
||||
readRows++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
while ( rowProcessingState.next() ) {
|
||||
results.add( rowReader.readRow( rowProcessingState, processingOptions ) );
|
||||
rowProcessingState.finishRowProcessing();
|
||||
readRows++;
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
rowReader.finishUp( jdbcValuesSourceProcessingState );
|
||||
jdbcValuesSourceProcessingState.finishUp();
|
||||
jdbcValuesSourceProcessingState.finishUp( readRows > 1 );
|
||||
}
|
||||
finally {
|
||||
persistenceContext.getLoadContexts().deregister( jdbcValuesSourceProcessingState );
|
||||
|
|
|
@ -15,7 +15,6 @@ import org.hibernate.internal.CoreMessageLogger;
|
|||
import org.hibernate.internal.util.collections.StandardStack;
|
||||
import org.hibernate.sql.results.graph.Initializer;
|
||||
import org.hibernate.sql.results.graph.collection.LoadingCollectionEntry;
|
||||
import org.hibernate.sql.results.graph.entity.LoadingEntityEntry;
|
||||
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
|
||||
|
||||
/**
|
||||
|
@ -51,10 +50,6 @@ public class LoadContexts {
|
|||
return jdbcValuesSourceProcessingStateStack.getRoot() == null;
|
||||
}
|
||||
|
||||
public LoadingEntityEntry findLoadingEntityEntry(final EntityKey entityKey) {
|
||||
return jdbcValuesSourceProcessingStateStack.findCurrentFirstWithParameter( entityKey, JdbcValuesSourceProcessingState::findLoadingEntityLocally );
|
||||
}
|
||||
|
||||
public LoadingCollectionEntry findLoadingCollectionEntry(final CollectionKey collectionKey) {
|
||||
return jdbcValuesSourceProcessingStateStack.findCurrentFirstWithParameter( collectionKey, JdbcValuesSourceProcessingState::findLoadingCollectionLocally );
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ public class SubselectTest {
|
|||
List<String> sqlQueries = statementInspector.getSqlQueries();
|
||||
assertThat( sqlQueries.size() ).isEqualTo( 1 );
|
||||
String query = sqlQueries.get( 0 );
|
||||
assertFalse( containsSubquery( query ), " The query should contain a subquery" );
|
||||
assertFalse( containsSubquery( query ), " The query should not contain a subquery" );
|
||||
|
||||
}
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue