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.SharedSessionContractImplementor;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
|
@ -130,8 +131,16 @@ public abstract class AbstractBatchEntitySelectFetchInitializer extends Abstract
|
|||
);
|
||||
}
|
||||
|
||||
protected static int getPropertyIndex(EntityInitializer entityInitializer, String propertyName) {
|
||||
return entityInitializer.getConcreteDescriptor().findAttributeMapping( propertyName ).getStateArrayPosition();
|
||||
protected AttributeMapping getParentEntityAttribute(String attributeName) {
|
||||
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
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.engine.spi.EntityKey;
|
|||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.log.LoggingHelper;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
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;
|
||||
|
||||
public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractBatchEntitySelectFetchInitializer {
|
||||
private final Map<EntityKey, List<ParentInfo>> toBatchLoad = new HashMap<>();
|
||||
private Map<EntityKey, List<ParentInfo>> toBatchLoad;
|
||||
private final String rootEmbeddablePropertyName;
|
||||
|
||||
/**
|
||||
|
@ -71,27 +72,23 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
|
|||
|
||||
@Override
|
||||
protected void registerResolutionListener() {
|
||||
final List<ParentInfo> batchParentInfos = getBatchInfos();
|
||||
|
||||
parentAccess.registerResolutionListener(
|
||||
o ->
|
||||
batchParentInfos.add(
|
||||
new ParentInfo(
|
||||
firstEntityInitializer.getEntityKey(),
|
||||
o,
|
||||
getPropertyIndex( firstEntityInitializer, rootEmbeddablePropertyName )
|
||||
)
|
||||
)
|
||||
);
|
||||
parentAccess.registerResolutionListener( parentInstance -> {
|
||||
final AttributeMapping parentAttribute = getParentEntityAttribute( rootEmbeddablePropertyName );
|
||||
if ( parentAttribute != null ) {
|
||||
getParentInfos().add( new ParentInfo(
|
||||
firstEntityInitializer.getEntityKey(),
|
||||
parentInstance,
|
||||
parentAttribute.getStateArrayPosition()
|
||||
) );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private List<ParentInfo> getBatchInfos() {
|
||||
List<ParentInfo> objects = toBatchLoad.get( entityKey );
|
||||
if ( objects == null ) {
|
||||
objects = new ArrayList<>();
|
||||
toBatchLoad.put( entityKey, objects );
|
||||
private List<ParentInfo> getParentInfos() {
|
||||
if ( toBatchLoad == null ) {
|
||||
toBatchLoad = new HashMap<>();
|
||||
}
|
||||
return objects;
|
||||
return toBatchLoad.computeIfAbsent( entityKey, key -> new ArrayList<>() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -113,27 +110,29 @@ public class BatchEntityInsideEmbeddableSelectFetchInitializer extends AbstractB
|
|||
|
||||
@Override
|
||||
public void endLoading(ExecutionContext context) {
|
||||
toBatchLoad.forEach(
|
||||
(entityKey, parentInfos) -> {
|
||||
final SharedSessionContractImplementor session = context.getSession();
|
||||
final Object loadedInstance = loadInstance( entityKey, referencedModelPart, session );
|
||||
for ( ParentInfo parentInfo : parentInfos ) {
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
setInstance(
|
||||
firstEntityInitializer,
|
||||
referencedModelPart,
|
||||
rootEmbeddablePropertyName,
|
||||
parentInfo.propertyIndex,
|
||||
loadedInstance,
|
||||
parentInfo.parentInstance,
|
||||
parentInfo.initializerEntityKey,
|
||||
persistenceContext.getEntry( persistenceContext.getEntity( parentInfo.initializerEntityKey ) ),
|
||||
session
|
||||
);
|
||||
if ( toBatchLoad != null ) {
|
||||
toBatchLoad.forEach(
|
||||
(entityKey, parentInfos) -> {
|
||||
final SharedSessionContractImplementor session = context.getSession();
|
||||
final Object loadedInstance = loadInstance( entityKey, referencedModelPart, session );
|
||||
for ( ParentInfo parentInfo : parentInfos ) {
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContext();
|
||||
setInstance(
|
||||
firstEntityInitializer,
|
||||
referencedModelPart,
|
||||
rootEmbeddablePropertyName,
|
||||
parentInfo.propertyIndex,
|
||||
loadedInstance,
|
||||
parentInfo.parentInstance,
|
||||
parentInfo.initializerEntityKey,
|
||||
persistenceContext.getEntry( persistenceContext.getEntity( parentInfo.initializerEntityKey ) ),
|
||||
session
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
toBatchLoad.clear();
|
||||
);
|
||||
toBatchLoad.clear();
|
||||
}
|
||||
parentAccess = null;
|
||||
}
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@ import org.hibernate.engine.spi.EntityEntry;
|
|||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.log.LoggingHelper;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
@ -24,7 +25,7 @@ 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<ParentInfo>> toBatchLoad = new HashMap<>();
|
||||
private Map<EntityKey, List<ParentInfo>> toBatchLoad;
|
||||
|
||||
public BatchEntitySelectFetchInitializer(
|
||||
FetchParentAccess parentAccess,
|
||||
|
@ -37,25 +38,19 @@ public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelect
|
|||
|
||||
@Override
|
||||
protected void registerResolutionListener() {
|
||||
final List<ParentInfo> parents = getParentInfos();
|
||||
parentAccess.registerResolutionListener(
|
||||
o ->
|
||||
parents.add(
|
||||
new ParentInfo(
|
||||
o,
|
||||
getPropertyIndex( firstEntityInitializer, referencedModelPart.getPartName() )
|
||||
)
|
||||
)
|
||||
);
|
||||
parentAccess.registerResolutionListener( parentInstance -> {
|
||||
final AttributeMapping parentAttribute = getParentEntityAttribute( referencedModelPart.getAttributeName() );
|
||||
if ( parentAttribute != null ) {
|
||||
getParentInfos().add( new ParentInfo( parentInstance, parentAttribute.getStateArrayPosition() ) );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
private List<ParentInfo> getParentInfos() {
|
||||
List<ParentInfo> objects = toBatchLoad.get( entityKey );
|
||||
if ( objects == null ) {
|
||||
objects = new ArrayList<>();
|
||||
toBatchLoad.put( entityKey, objects );
|
||||
if ( toBatchLoad == null ) {
|
||||
toBatchLoad = new HashMap<>();
|
||||
}
|
||||
return objects;
|
||||
return toBatchLoad.computeIfAbsent( entityKey, key -> new ArrayList<>() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -75,26 +70,28 @@ public class BatchEntitySelectFetchInitializer extends AbstractBatchEntitySelect
|
|||
|
||||
@Override
|
||||
public void endLoading(ExecutionContext context) {
|
||||
toBatchLoad.forEach(
|
||||
(entityKey, parentInfos) -> {
|
||||
final SharedSessionContractImplementor session = context.getSession();
|
||||
final Object instance = loadInstance( entityKey, referencedModelPart, session );
|
||||
for ( ParentInfo parentInfo : parentInfos ) {
|
||||
final Object parentInstance = parentInfo.parentInstance;
|
||||
setInstance(
|
||||
firstEntityInitializer,
|
||||
referencedModelPart,
|
||||
referencedModelPart.getPartName(),
|
||||
parentInfo.propertyIndex,
|
||||
session,
|
||||
instance,
|
||||
parentInstance,
|
||||
session.getPersistenceContext().getEntry( parentInstance )
|
||||
);
|
||||
if ( toBatchLoad != null ) {
|
||||
toBatchLoad.forEach(
|
||||
(entityKey, parentInfos) -> {
|
||||
final SharedSessionContractImplementor session = context.getSession();
|
||||
final Object instance = loadInstance( entityKey, referencedModelPart, session );
|
||||
for ( ParentInfo parentInfo : parentInfos ) {
|
||||
final Object parentInstance = parentInfo.parentInstance;
|
||||
setInstance(
|
||||
firstEntityInitializer,
|
||||
referencedModelPart,
|
||||
referencedModelPart.getPartName(),
|
||||
parentInfo.propertyIndex,
|
||||
session,
|
||||
instance,
|
||||
parentInstance,
|
||||
session.getPersistenceContext().getEntry( parentInstance )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
toBatchLoad.clear();
|
||||
);
|
||||
toBatchLoad.clear();
|
||||
}
|
||||
parentAccess = null;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue