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

View File

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

View File

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