HHH-15694 HibernateException: Unable to resolve property xyz on ManyToOne with BatchSize

This commit is contained in:
Andrea Boriero 2022-11-15 19:03:23 +01:00 committed by Andrea Boriero
parent 47933b36bd
commit d25c1a44f0
3 changed files with 82 additions and 46 deletions

View File

@ -27,8 +27,9 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
private final NavigablePath navigablePath; private final NavigablePath navigablePath;
protected final EntityPersister concreteDescriptor; protected final EntityPersister concreteDescriptor;
protected final DomainResultAssembler identifierAssembler; protected final DomainResultAssembler<?> identifierAssembler;
protected final ToOneAttributeMapping referencedModelPart; protected final ToOneAttributeMapping referencedModelPart;
protected final EntityInitializer firstEntityInitializer;
protected Object entityInstance; protected Object entityInstance;
protected EntityKey entityKey; protected EntityKey entityKey;
@ -38,12 +39,13 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
ToOneAttributeMapping referencedModelPart, ToOneAttributeMapping referencedModelPart,
NavigablePath fetchedNavigable, NavigablePath fetchedNavigable,
EntityPersister concreteDescriptor, EntityPersister concreteDescriptor,
DomainResultAssembler identifierAssembler) { DomainResultAssembler<?> identifierAssembler) {
this.parentAccess = parentAccess; this.parentAccess = parentAccess;
this.referencedModelPart = referencedModelPart; this.referencedModelPart = referencedModelPart;
this.navigablePath = fetchedNavigable; this.navigablePath = fetchedNavigable;
this.concreteDescriptor = concreteDescriptor; this.concreteDescriptor = concreteDescriptor;
this.identifierAssembler = identifierAssembler; this.identifierAssembler = identifierAssembler;
this.firstEntityInitializer = parentAccess.findFirstEntityInitializer();
} }
public ModelPart getInitializedPart() { public ModelPart getInitializedPart() {
@ -62,9 +64,11 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
return; return;
} }
entityKey = new EntityKey( entityIdentifier, concreteDescriptor ); entityKey = new EntityKey( entityIdentifier, concreteDescriptor );
addParentInfo();
rowProcessingState.getSession().getPersistenceContext() rowProcessingState.getSession().getPersistenceContext()
.getBatchFetchQueue().addBatchLoadableEntityKey( entityKey ); .getBatchFetchQueue().addBatchLoadableEntityKey( entityKey );
registerResolutionListener();
} }
@Override @Override
@ -75,7 +79,7 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
public void initializeInstance(RowProcessingState rowProcessingState) { public void initializeInstance(RowProcessingState rowProcessingState) {
} }
protected abstract void addParentInfo(); protected abstract void registerResolutionListener();
@Override @Override
public void finishUpRow(RowProcessingState rowProcessingState) { public void finishUpRow(RowProcessingState rowProcessingState) {
@ -125,8 +129,8 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
); );
} }
protected static int getPropertyIndex(FetchParentAccess parentAccess, String propertyName) { protected static int getPropertyIndex(EntityInitializer entityInitializer, String propertyName) {
return parentAccess.findFirstEntityInitializer().getEntityDescriptor().getPropertyIndex( propertyName ); return entityInitializer.getConcreteDescriptor().getPropertyIndex( propertyName );
} }
@Override @Override

View File

@ -27,10 +27,8 @@ import org.hibernate.sql.results.graph.entity.EntityInitializer;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState; import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractBatchEntitySelectFetchInitializer { public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractBatchEntitySelectFetchInitializer {
/* private final Map<EntityKey, List<ParentInfo>> toBatchLoad = new HashMap<>();
Object[0] will contain the parent EntityKey and Object[1] the parent embeddable instance, private final String rootEmbeddablePropertyName;
*/
private final Map<EntityKey, List<Object[]>> toBatchLoad = new HashMap<>();
/** /**
* Marker value for batch properties, needed by the EmbeddableInitializer to instantiate the * Marker value for batch properties, needed by the EmbeddableInitializer to instantiate the
@ -52,8 +50,14 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
ToOneAttributeMapping referencedModelPart, ToOneAttributeMapping referencedModelPart,
NavigablePath fetchedNavigable, NavigablePath fetchedNavigable,
EntityPersister concreteDescriptor, EntityPersister concreteDescriptor,
DomainResultAssembler identifierAssembler) { DomainResultAssembler<?> identifierAssembler) {
super( parentAccess, referencedModelPart, fetchedNavigable, concreteDescriptor, identifierAssembler ); super( parentAccess, referencedModelPart, fetchedNavigable, concreteDescriptor, identifierAssembler );
rootEmbeddablePropertyName = getRootEmbeddablePropertyName(
firstEntityInitializer,
parentAccess,
referencedModelPart
);
} }
@Override @Override
@ -66,21 +70,23 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
} }
@Override @Override
protected void addParentInfo() { protected void registerResolutionListener() {
final List<Object[]> parents = getBatchInfos(); final List<ParentInfo> batchParentInfos = getBatchInfos();
parentAccess.registerResolutionListener( parentAccess.registerResolutionListener(
o -> o ->
parents.add( batchParentInfos.add(
new Object[] { new ParentInfo(
parentAccess.findFirstEntityInitializer().getEntityKey(), firstEntityInitializer.getEntityKey(),
o o,
} getPropertyIndex( firstEntityInitializer, rootEmbeddablePropertyName )
) )
)
); );
} }
private List<Object[]> getBatchInfos() { private List<ParentInfo> getBatchInfos() {
List<Object[]> objects = toBatchLoad.get( entityKey ); List<ParentInfo> objects = toBatchLoad.get( entityKey );
if ( objects == null ) { if ( objects == null ) {
objects = new ArrayList<>(); objects = new ArrayList<>();
toBatchLoad.put( entityKey, objects ); toBatchLoad.put( entityKey, objects );
@ -88,26 +94,35 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
return objects; return objects;
} }
private static class ParentInfo {
private final EntityKey initializerEntityKey;
private final Object parentInstance;
private final int propertyIndex;
public ParentInfo(EntityKey initializerEntityKey, Object parentInstance, int propertyIndex) {
this.initializerEntityKey = initializerEntityKey;
this.parentInstance = parentInstance;
this.propertyIndex = propertyIndex;
}
}
@Override @Override
public void endLoading(ExecutionContext context) { public void endLoading(ExecutionContext context) {
final EntityInitializer entityInitializer = parentAccess.findFirstEntityInitializer();
final String rootEmbeddablePropertyName = getRootEmbeddablePropertyName();
final int rootEmbeddablePropertyIndex = getPropertyIndex( parentAccess, rootEmbeddablePropertyName );
toBatchLoad.forEach( toBatchLoad.forEach(
(entityKey, parentInfos) -> { (entityKey, parentInfos) -> {
final SharedSessionContractImplementor session = context.getSession(); final SharedSessionContractImplementor session = context.getSession();
final Object loadedInstance = loadInstance( entityKey, referencedModelPart, session ); final Object loadedInstance = loadInstance( entityKey, referencedModelPart, session );
for ( Object[] parentInfo : parentInfos ) { for ( ParentInfo parentInfo : parentInfos ) {
final PersistenceContext persistenceContext = session.getPersistenceContext(); final PersistenceContext persistenceContext = session.getPersistenceContext();
setInstance( setInstance(
entityInitializer, firstEntityInitializer,
referencedModelPart, referencedModelPart,
rootEmbeddablePropertyName, rootEmbeddablePropertyName,
rootEmbeddablePropertyIndex, parentInfo.propertyIndex,
loadedInstance, loadedInstance,
parentInfo[1], parentInfo.parentInstance,
(EntityKey) parentInfo[0], parentInfo.initializerEntityKey,
persistenceContext.getEntry( persistenceContext.getEntity( (EntityKey) parentInfo[0] ) ), persistenceContext.getEntry( persistenceContext.getEntity( parentInfo.initializerEntityKey ) ),
session session
); );
} }
@ -164,8 +179,11 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
} }
} }
protected String getRootEmbeddablePropertyName() { protected static String getRootEmbeddablePropertyName(
final NavigablePath entityPath = parentAccess.findFirstEntityDescriptorAccess().getNavigablePath(); EntityInitializer firstEntityInitializer,
FetchParentAccess parentAccess,
ToOneAttributeMapping referencedModelPart) {
final NavigablePath entityPath = firstEntityInitializer.getNavigablePath();
NavigablePath navigablePath = parentAccess.getNavigablePath(); NavigablePath navigablePath = parentAccess.getNavigablePath();
if ( navigablePath == entityPath ) { if ( navigablePath == entityPath ) {
return referencedModelPart.getPartName(); return referencedModelPart.getPartName();

View File

@ -24,27 +24,33 @@ import org.hibernate.sql.results.graph.FetchParentAccess;
import org.hibernate.sql.results.graph.entity.EntityInitializer; import org.hibernate.sql.results.graph.entity.EntityInitializer;
public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelectFetchInitializer { public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelectFetchInitializer {
private final Map<EntityKey, List<Object>> toBatchLoad = new HashMap<>(); private final Map<EntityKey, List<ParentInfo>> toBatchLoad = new HashMap<>();
public BatchEntitySelectFetchInitializer( public BatchEntitySelectFetchInitializer(
FetchParentAccess parentAccess, FetchParentAccess parentAccess,
ToOneAttributeMapping referencedModelPart, ToOneAttributeMapping referencedModelPart,
NavigablePath fetchedNavigable, NavigablePath fetchedNavigable,
EntityPersister concreteDescriptor, EntityPersister concreteDescriptor,
DomainResultAssembler identifierAssembler) { DomainResultAssembler<?> identifierAssembler) {
super( parentAccess, referencedModelPart, fetchedNavigable, concreteDescriptor, identifierAssembler ); super( parentAccess, referencedModelPart, fetchedNavigable, concreteDescriptor, identifierAssembler );
} }
@Override @Override
protected void addParentInfo() { protected void registerResolutionListener() {
final List<Object> parents = getBatchInfos(); final List<ParentInfo> parents = getParentInfos();
parentAccess.registerResolutionListener( parentAccess.registerResolutionListener(
o -> parents.add( o ) o ->
parents.add(
new ParentInfo(
o,
getPropertyIndex( firstEntityInitializer, referencedModelPart.getPartName() )
)
)
); );
} }
private List<Object> getBatchInfos() { private List<ParentInfo> getParentInfos() {
List<Object> objects = toBatchLoad.get( entityKey ); List<ParentInfo> objects = toBatchLoad.get( entityKey );
if ( objects == null ) { if ( objects == null ) {
objects = new ArrayList<>(); objects = new ArrayList<>();
toBatchLoad.put( entityKey, objects ); toBatchLoad.put( entityKey, objects );
@ -52,21 +58,29 @@ public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelect
return objects; return objects;
} }
private static class ParentInfo {
private final Object parentInstance;
private final int propertyIndex;
public ParentInfo(Object parentInstance, int propertyIndex) {
this.parentInstance = parentInstance;
this.propertyIndex = propertyIndex;
}
}
@Override @Override
public void endLoading(ExecutionContext context) { public void endLoading(ExecutionContext context) {
final EntityInitializer entityInitializer = parentAccess.findFirstEntityInitializer();
final String propertyName = referencedModelPart.getPartName();
final int propertyIndex = getPropertyIndex( parentAccess, propertyName );
toBatchLoad.forEach( toBatchLoad.forEach(
(entityKey, parentInfos) -> { (entityKey, parentInfos) -> {
final SharedSessionContractImplementor session = context.getSession(); final SharedSessionContractImplementor session = context.getSession();
final Object instance = loadInstance( entityKey, referencedModelPart, session ); final Object instance = loadInstance( entityKey, referencedModelPart, session );
for ( Object parentInstance : parentInfos ) { for ( ParentInfo parentInfo : parentInfos ) {
final Object parentInstance = parentInfo.parentInstance;
setInstance( setInstance(
entityInitializer, firstEntityInitializer,
referencedModelPart, referencedModelPart,
propertyName, referencedModelPart.getPartName(),
propertyIndex, parentInfo.propertyIndex,
session, session,
instance, instance,
parentInstance, parentInstance,