HHH-15694 HibernateException: Unable to resolve property xyz on ManyToOne with BatchSize
This commit is contained in:
parent
47933b36bd
commit
d25c1a44f0
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Reference in New Issue