HHH-16248 Check referenced model part declaring type when batch fetching associations
This commit is contained in:
parent
f572f80f6e
commit
837d1a32cb
|
@ -10,6 +10,7 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.ModelPart;
|
import org.hibernate.metamodel.mapping.ModelPart;
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
|
@ -130,8 +131,16 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static int getPropertyIndex(EntityInitializer entityInitializer, String propertyName) {
|
protected AttributeMapping getParentEntityAttribute(String attributeName) {
|
||||||
return entityInitializer.getConcreteDescriptor().findAttributeMapping( propertyName ).getStateArrayPosition();
|
final AttributeMapping parentAttribute = firstEntityInitializer.getConcreteDescriptor()
|
||||||
|
.findAttributeMapping( attributeName );
|
||||||
|
if ( parentAttribute != null && parentAttribute.getDeclaringType() == referencedModelPart.getDeclaringType()
|
||||||
|
.findContainingEntityMapping() ) {
|
||||||
|
// These checks are needed to avoid setting the instance using the wrong (child's) model part or
|
||||||
|
// setting it multiple times in case parent and child share the same attribute name for the association.
|
||||||
|
return parentAttribute;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.PersistenceContext;
|
import org.hibernate.engine.spi.PersistenceContext;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.log.LoggingHelper;
|
import org.hibernate.internal.log.LoggingHelper;
|
||||||
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
|
@ -27,7 +28,7 @@ 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<>();
|
private Map<EntityKey, List<ParentInfo>> toBatchLoad;
|
||||||
private final String rootEmbeddablePropertyName;
|
private final String rootEmbeddablePropertyName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,27 +72,23 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void registerResolutionListener() {
|
protected void registerResolutionListener() {
|
||||||
final List<ParentInfo> batchParentInfos = getBatchInfos();
|
parentAccess.registerResolutionListener( parentInstance -> {
|
||||||
|
final AttributeMapping parentAttribute = getParentEntityAttribute( rootEmbeddablePropertyName );
|
||||||
parentAccess.registerResolutionListener(
|
if ( parentAttribute != null ) {
|
||||||
o ->
|
getParentInfos().add( new ParentInfo(
|
||||||
batchParentInfos.add(
|
firstEntityInitializer.getEntityKey(),
|
||||||
new ParentInfo(
|
parentInstance,
|
||||||
firstEntityInitializer.getEntityKey(),
|
parentAttribute.getStateArrayPosition()
|
||||||
o,
|
) );
|
||||||
getPropertyIndex( firstEntityInitializer, rootEmbeddablePropertyName )
|
}
|
||||||
)
|
} );
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ParentInfo> getBatchInfos() {
|
private List<ParentInfo> getParentInfos() {
|
||||||
List<ParentInfo> objects = toBatchLoad.get( entityKey );
|
if ( toBatchLoad == null ) {
|
||||||
if ( objects == null ) {
|
toBatchLoad = new HashMap<>();
|
||||||
objects = new ArrayList<>();
|
|
||||||
toBatchLoad.put( entityKey, objects );
|
|
||||||
}
|
}
|
||||||
return objects;
|
return toBatchLoad.computeIfAbsent( entityKey, key -> new ArrayList<>() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -113,27 +110,29 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endLoading(ExecutionContext context) {
|
public void endLoading(ExecutionContext context) {
|
||||||
toBatchLoad.forEach(
|
if ( toBatchLoad != null ) {
|
||||||
(entityKey, parentInfos) -> {
|
toBatchLoad.forEach(
|
||||||
final SharedSessionContractImplementor session = context.getSession();
|
(entityKey, parentInfos) -> {
|
||||||
final Object loadedInstance = loadInstance( entityKey, referencedModelPart, session );
|
final SharedSessionContractImplementor session = context.getSession();
|
||||||
for ( ParentInfo parentInfo : parentInfos ) {
|
final Object loadedInstance = loadInstance( entityKey, referencedModelPart, session );
|
||||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
for ( ParentInfo parentInfo : parentInfos ) {
|
||||||
setInstance(
|
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||||
firstEntityInitializer,
|
setInstance(
|
||||||
referencedModelPart,
|
firstEntityInitializer,
|
||||||
rootEmbeddablePropertyName,
|
referencedModelPart,
|
||||||
parentInfo.propertyIndex,
|
rootEmbeddablePropertyName,
|
||||||
loadedInstance,
|
parentInfo.propertyIndex,
|
||||||
parentInfo.parentInstance,
|
loadedInstance,
|
||||||
parentInfo.initializerEntityKey,
|
parentInfo.parentInstance,
|
||||||
persistenceContext.getEntry( persistenceContext.getEntity( parentInfo.initializerEntityKey ) ),
|
parentInfo.initializerEntityKey,
|
||||||
session
|
persistenceContext.getEntry( persistenceContext.getEntity( parentInfo.initializerEntityKey ) ),
|
||||||
);
|
session
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
toBatchLoad.clear();
|
||||||
toBatchLoad.clear();
|
}
|
||||||
parentAccess = null;
|
parentAccess = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.engine.spi.EntityEntry;
|
||||||
import org.hibernate.engine.spi.EntityKey;
|
import org.hibernate.engine.spi.EntityKey;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.internal.log.LoggingHelper;
|
import org.hibernate.internal.log.LoggingHelper;
|
||||||
|
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.spi.NavigablePath;
|
import org.hibernate.spi.NavigablePath;
|
||||||
|
@ -24,7 +25,7 @@ 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<ParentInfo>> toBatchLoad = new HashMap<>();
|
private Map<EntityKey, List<ParentInfo>> toBatchLoad;
|
||||||
|
|
||||||
public BatchEntitySelectFetchInitializer(
|
public BatchEntitySelectFetchInitializer(
|
||||||
FetchParentAccess parentAccess,
|
FetchParentAccess parentAccess,
|
||||||
|
@ -37,25 +38,19 @@ public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void registerResolutionListener() {
|
protected void registerResolutionListener() {
|
||||||
final List<ParentInfo> parents = getParentInfos();
|
parentAccess.registerResolutionListener( parentInstance -> {
|
||||||
parentAccess.registerResolutionListener(
|
final AttributeMapping parentAttribute = getParentEntityAttribute( referencedModelPart.getAttributeName() );
|
||||||
o ->
|
if ( parentAttribute != null ) {
|
||||||
parents.add(
|
getParentInfos().add( new ParentInfo( parentInstance, parentAttribute.getStateArrayPosition() ) );
|
||||||
new ParentInfo(
|
}
|
||||||
o,
|
} );
|
||||||
getPropertyIndex( firstEntityInitializer, referencedModelPart.getPartName() )
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ParentInfo> getParentInfos() {
|
private List<ParentInfo> getParentInfos() {
|
||||||
List<ParentInfo> objects = toBatchLoad.get( entityKey );
|
if ( toBatchLoad == null ) {
|
||||||
if ( objects == null ) {
|
toBatchLoad = new HashMap<>();
|
||||||
objects = new ArrayList<>();
|
|
||||||
toBatchLoad.put( entityKey, objects );
|
|
||||||
}
|
}
|
||||||
return objects;
|
return toBatchLoad.computeIfAbsent( entityKey, key -> new ArrayList<>() );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -75,26 +70,28 @@ public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelect
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void endLoading(ExecutionContext context) {
|
public void endLoading(ExecutionContext context) {
|
||||||
toBatchLoad.forEach(
|
if ( toBatchLoad != null ) {
|
||||||
(entityKey, parentInfos) -> {
|
toBatchLoad.forEach(
|
||||||
final SharedSessionContractImplementor session = context.getSession();
|
(entityKey, parentInfos) -> {
|
||||||
final Object instance = loadInstance( entityKey, referencedModelPart, session );
|
final SharedSessionContractImplementor session = context.getSession();
|
||||||
for ( ParentInfo parentInfo : parentInfos ) {
|
final Object instance = loadInstance( entityKey, referencedModelPart, session );
|
||||||
final Object parentInstance = parentInfo.parentInstance;
|
for ( ParentInfo parentInfo : parentInfos ) {
|
||||||
setInstance(
|
final Object parentInstance = parentInfo.parentInstance;
|
||||||
firstEntityInitializer,
|
setInstance(
|
||||||
referencedModelPart,
|
firstEntityInitializer,
|
||||||
referencedModelPart.getPartName(),
|
referencedModelPart,
|
||||||
parentInfo.propertyIndex,
|
referencedModelPart.getPartName(),
|
||||||
session,
|
parentInfo.propertyIndex,
|
||||||
instance,
|
session,
|
||||||
parentInstance,
|
instance,
|
||||||
session.getPersistenceContext().getEntry( parentInstance )
|
parentInstance,
|
||||||
);
|
session.getPersistenceContext().getEntry( parentInstance )
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
);
|
toBatchLoad.clear();
|
||||||
toBatchLoad.clear();
|
}
|
||||||
parentAccess = null;
|
parentAccess = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue