HHH-17359 Assemble key for select fetch initializers in resolveInstance phase

This commit is contained in:
Marco Belladelli 2023-10-26 11:15:32 +02:00 committed by Christian Beikov
parent 25c2d6ac48
commit 52e6e1fc0f
3 changed files with 79 additions and 43 deletions

View File

@ -517,12 +517,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
else {
entityInstance = proxy;
if ( Hibernate.isInitialized( entityInstance ) ) {
this.isInitialized = true;
registerReloadedEntity( rowProcessingState, holder );
if ( rowProcessingState.getQueryOptions().isResultCachingEnabled() == Boolean.TRUE ) {
// We need to read result set values to correctly populate the query cache
resolveState( rowProcessingState );
}
this.isInitialized = true;
}
}
}
@ -532,13 +532,13 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
entityInstance = existingEntity;
if ( holder.getEntityInitializer() == null ) {
if ( isExistingEntityInitialized( existingEntity ) ) {
this.isInitialized = true;
registerReloadedEntity( rowProcessingState, holder );
notifyResolutionListeners( entityInstance );
if ( rowProcessingState.getQueryOptions().isResultCachingEnabled() == Boolean.TRUE ) {
// We need to read result set values to correctly populate the query cache
resolveState( rowProcessingState );
}
this.isInitialized = true;
}
else {
registerLoadingEntityInstanceFromExecutionContext( rowProcessingState, entityInstance );

View File

@ -10,8 +10,10 @@ import org.hibernate.engine.spi.EntityUniqueKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.log.LoggingHelper;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.FetchParentAccess;
@ -37,31 +39,55 @@ public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchIn
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( entityInstance != null || isInitialized ) {
public void resolveInstance(RowProcessingState rowProcessingState) {
if ( state != State.UNINITIALIZED ) {
return;
}
state = State.RESOLVED;
final EntityInitializer parentEntityInitializer = getParentEntityInitializer( parentAccess );
if ( parentEntityInitializer != null && parentEntityInitializer.getEntityKey() != null ) {
// make sure parentEntityInitializer.resolveInstance has been called before
parentEntityInitializer.resolveInstance( rowProcessingState );
if ( parentEntityInitializer.isEntityInitialized() ) {
isInitialized = true;
state = State.INITIALIZED;
return;
}
}
if ( !isAttributeAssignableToConcreteDescriptor() ) {
isInitialized = true;
state = State.INITIALIZED;
return;
}
final Object entityIdentifier = keyAssembler.assemble( rowProcessingState );
entityIdentifier = keyAssembler.assemble( rowProcessingState );
if ( entityIdentifier == null ) {
isInitialized = true;
state = State.INITIALIZED;
return;
}
// Defer the select by default to the initialize phase
// We only need to select in this phase if this is part of an identifier or foreign key
NavigablePath np = getNavigablePath().getParent();
while ( np != null ) {
if ( np instanceof EntityIdentifierNavigablePath
|| ForeignKeyDescriptor.PART_NAME.equals( np.getLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( np.getLocalName() )) {
initializeInstance( rowProcessingState );
return;
}
np = np.getParent();
}
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( state == State.INITIALIZED ) {
return;
}
state = State.INITIALIZED;
final String entityName = concreteDescriptor.getEntityName();
final String uniqueKeyPropertyName = fetchedAttribute.getReferencedPropertyName();
@ -103,7 +129,6 @@ public class EntitySelectFetchByUniqueKeyInitializer extends EntitySelectFetchIn
if ( entityInstance != null ) {
entityInstance = persistenceContext.proxyFor( entityInstance );
}
isInitialized = true;
}
private EntityInitializer getParentEntityInitializer(FetchParentAccess parentAccess) {

View File

@ -48,15 +48,15 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
protected final DomainResultAssembler<?> keyAssembler;
private final ToOneAttributeMapping toOneMapping;
protected boolean isInitialized;
protected State state = State.UNINITIALIZED;
protected Object entityIdentifier;
protected Object entityInstance;
@Override
public FetchParentAccess getFetchParentAccess() {
return parentAccess;
}
protected Object entityInstance;
public EntitySelectFetchInitializer(
FetchParentAccess parentAccess,
ToOneAttributeMapping toOneMapping,
@ -87,41 +87,26 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
@Override
public void resolveInstance(RowProcessingState rowProcessingState) {
// Defer the select by default to the initialize phase
// We only need to select in this phase if this is part of an identifier or foreign key
NavigablePath np = navigablePath.getParent();
while ( np != null ) {
if ( np instanceof EntityIdentifierNavigablePath
|| ForeignKeyDescriptor.PART_NAME.equals( np.getLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( np.getLocalName() )) {
initializeInstance( rowProcessingState );
return;
}
np = np.getParent();
}
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( entityInstance != null || isInitialized ) {
if ( state != State.UNINITIALIZED ) {
return;
}
state = State.RESOLVED;
final EntityInitializer parentEntityInitializer = parentAccess.findFirstEntityInitializer();
if ( parentEntityInitializer != null && parentEntityInitializer.isEntityInitialized() ) {
isInitialized = true;
state = State.INITIALIZED;
return;
}
if ( !isAttributeAssignableToConcreteDescriptor() ) {
state = State.INITIALIZED;
return;
}
final Object entityIdentifier = keyAssembler.assemble( rowProcessingState );
entityIdentifier = keyAssembler.assemble( rowProcessingState );
if ( entityIdentifier == null ) {
isInitialized = true;
state = State.INITIALIZED;
return;
}
@ -134,8 +119,6 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
);
}
final SharedSessionContractImplementor session = rowProcessingState.getSession();
final String entityName = concreteDescriptor.getEntityName();
final EntityKey entityKey = new EntityKey( entityIdentifier, concreteDescriptor );
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
@ -154,7 +137,7 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
entityInstance = holder.getEntity();
if ( holder.getEntityInitializer() == null ) {
if ( entityInstance != null && Hibernate.isInitialized( entityInstance ) ) {
isInitialized = true;
state = State.INITIALIZED;
return;
}
}
@ -168,15 +151,39 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
holder.getEntityInitializer()
);
}
isInitialized = true;
state = State.INITIALIZED;
return;
}
else if ( entityInstance == null ) {
isInitialized = true;
state = State.INITIALIZED;
return;
}
}
// Defer the select by default to the initialize phase
// We only need to select in this phase if this is part of an identifier or foreign key
NavigablePath np = navigablePath.getParent();
while ( np != null ) {
if ( np instanceof EntityIdentifierNavigablePath
|| ForeignKeyDescriptor.PART_NAME.equals( np.getLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( np.getLocalName() )) {
initializeInstance( rowProcessingState );
return;
}
np = np.getParent();
}
}
@Override
public void initializeInstance(RowProcessingState rowProcessingState) {
if ( state == State.INITIALIZED ) {
return;
}
state = State.INITIALIZED;
final SharedSessionContractImplementor session = rowProcessingState.getSession();
final String entityName = concreteDescriptor.getEntityName();
if ( EntityLoadingLogging.ENTITY_LOADING_LOGGER.isDebugEnabled() ) {
EntityLoadingLogging.ENTITY_LOADING_LOGGER.debugf(
"(%s) Invoking session#internalLoad for entity (%s) : %s",
@ -197,7 +204,7 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
throw new FetchNotFoundException( entityName, entityIdentifier );
}
rowProcessingState.getSession().getPersistenceContextInternal().claimEntityHolderIfPossible(
entityKey,
new EntityKey( entityIdentifier, concreteDescriptor ),
entityInstance,
rowProcessingState.getJdbcValuesSourceProcessingState(),
this
@ -218,8 +225,6 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
if ( lazyInitializer != null ) {
lazyInitializer.setUnwrap( unwrapProxy );
}
isInitialized = true;
}
protected boolean isAttributeAssignableToConcreteDescriptor() {
@ -229,7 +234,7 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
@Override
public void finishUpRow(RowProcessingState rowProcessingState) {
entityInstance = null;
isInitialized = false;
state = State.UNINITIALIZED;
clearResolutionListeners();
}
@ -250,7 +255,7 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
@Override
public boolean isEntityInitialized() {
return isInitialized;
return state == State.INITIALIZED;
}
@Override
@ -277,4 +282,10 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
public String toString() {
return "EntitySelectFetchInitializer(" + LoggingHelper.toLoggableString( getNavigablePath() ) + ")";
}
protected enum State {
UNINITIALIZED,
RESOLVED,
INITIALIZED;
}
}