HHH-16651 make persisters return adapted loaders for session batch size
This commit is contained in:
parent
3097c47b3d
commit
bbd8df93ca
|
@ -46,7 +46,7 @@ public class CollectionLoaderSubSelectFetch implements CollectionLoader {
|
|||
|
||||
public CollectionLoaderSubSelectFetch(
|
||||
PluralAttributeMapping attributeMapping,
|
||||
DomainResult cachedDomainResult,
|
||||
DomainResult<?> cachedDomainResult,
|
||||
SubselectFetch subselect,
|
||||
SharedSessionContractImplementor session) {
|
||||
this.attributeMapping = attributeMapping;
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.loader.ast.internal;
|
||||
|
||||
import java.lang.reflect.Array;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.LockOptions;
|
||||
|
@ -16,7 +15,6 @@ import org.hibernate.engine.spi.EntityKey;
|
|||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.SubselectFetch;
|
||||
import org.hibernate.loader.ast.spi.EntityBatchLoader;
|
||||
import org.hibernate.loader.ast.spi.SqlArrayMultiKeyLoader;
|
||||
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
|
||||
|
@ -26,15 +24,9 @@ import org.hibernate.metamodel.mapping.JdbcMapping;
|
|||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
|
||||
import org.hibernate.sql.ast.tree.select.SelectStatement;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterBindingsImpl;
|
||||
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
|
||||
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
||||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.BasicTypeRegistry;
|
||||
|
||||
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_DEBUG_ENABLED;
|
||||
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
|
||||
|
@ -162,13 +154,10 @@ public class EntityBatchLoaderArrayParam<T>
|
|||
@Override
|
||||
public void prepare() {
|
||||
identifierMapping = (BasicEntityIdentifierMapping) getLoadable().getIdentifierMapping();
|
||||
final Class<?> arrayClass = Array.newInstance( identifierMapping.getJavaType().getJavaTypeClass(), 0 ).getClass();
|
||||
|
||||
final BasicTypeRegistry basicTypeRegistry = sessionFactory.getTypeConfiguration().getBasicTypeRegistry();
|
||||
final BasicType<?> arrayBasicType = basicTypeRegistry.getRegisteredType( arrayClass );
|
||||
|
||||
final Class<?> arrayClass =
|
||||
Array.newInstance( identifierMapping.getJavaType().getJavaTypeClass(), 0 ).getClass();
|
||||
arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping(
|
||||
arrayBasicType,
|
||||
sessionFactory.getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ),
|
||||
identifierMapping.getJdbcMapping(),
|
||||
arrayClass,
|
||||
sessionFactory
|
||||
|
|
|
@ -56,16 +56,18 @@ public class EntityBatchLoaderInPredicate<T>
|
|||
|
||||
/**
|
||||
* @param domainBatchSize The maximum number of entities we will initialize for each {@link #load load}
|
||||
* @param sqlBatchSize The number of keys our SQL AST should be able to fetch
|
||||
*/
|
||||
public EntityBatchLoaderInPredicate(
|
||||
int domainBatchSize,
|
||||
int sqlBatchSize,
|
||||
EntityMappingType entityDescriptor,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( entityDescriptor, sessionFactory );
|
||||
this.domainBatchSize = domainBatchSize;
|
||||
this.sqlBatchSize = sqlBatchSize;
|
||||
int idColumnCount = entityDescriptor.getEntityPersister().getIdentifierType().getColumnSpan( sessionFactory );
|
||||
this.sqlBatchSize = sessionFactory.getJdbcServices()
|
||||
.getDialect()
|
||||
.getBatchLoadSizingStrategy()
|
||||
.determineOptimalBatchLoadSize( idColumnCount, domainBatchSize, false );
|
||||
|
||||
if ( MULTI_KEY_LOAD_DEBUG_ENABLED ) {
|
||||
MULTI_KEY_LOAD_LOGGER.debugf(
|
||||
|
|
|
@ -40,8 +40,6 @@ import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
|
|||
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
|
||||
import org.hibernate.sql.results.internal.RowTransformerStandardImpl;
|
||||
import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.BasicTypeRegistry;
|
||||
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
||||
|
@ -385,7 +383,7 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
|
|||
return ids;
|
||||
}
|
||||
|
||||
private <X> X[] createTypedArray(@SuppressWarnings("SameParameterValue") int length) {
|
||||
private <X> X[] createTypedArray(@SuppressWarnings("SameParameterValue") int length) {
|
||||
//noinspection unchecked
|
||||
return (X[]) Array.newInstance( getIdentifierMapping().getJavaType().getJavaTypeClass(), length );
|
||||
}
|
||||
|
@ -393,14 +391,9 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
|
|||
@Override
|
||||
public void prepare() {
|
||||
super.prepare();
|
||||
|
||||
final Class<?> arrayClass = createTypedArray( 0 ).getClass();
|
||||
|
||||
final BasicTypeRegistry basicTypeRegistry = getSessionFactory().getTypeConfiguration().getBasicTypeRegistry();
|
||||
final BasicType<?> arrayBasicType = basicTypeRegistry.getRegisteredType( arrayClass );
|
||||
|
||||
arrayJdbcMapping = MultiKeyLoadHelper.resolveArrayJdbcMapping(
|
||||
arrayBasicType,
|
||||
getSessionFactory().getTypeConfiguration().getBasicTypeRegistry().getRegisteredType( arrayClass ),
|
||||
getIdentifierMapping().getJdbcMapping(),
|
||||
arrayClass,
|
||||
getSessionFactory()
|
||||
|
|
|
@ -16,7 +16,6 @@ import org.hibernate.LockMode;
|
|||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.EntityEntry;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.PersistenceContext;
|
||||
|
@ -28,7 +27,6 @@ import org.hibernate.event.spi.LoadEvent;
|
|||
import org.hibernate.event.spi.LoadEventListener;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.spi.QueryOptions;
|
||||
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
|
||||
|
@ -54,10 +52,10 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
|||
|
||||
public MultiIdEntityLoaderStandard(
|
||||
EntityPersister entityDescriptor,
|
||||
PersistentClass bootDescriptor,
|
||||
int idColumnSpan,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
super( entityDescriptor, sessionFactory );
|
||||
this.idJdbcTypeCount = bootDescriptor.getIdentifier().getColumnSpan();
|
||||
this.idJdbcTypeCount = idColumnSpan;
|
||||
|
||||
assert idJdbcTypeCount > 0;
|
||||
}
|
||||
|
|
|
@ -18,9 +18,10 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.supportsSqlArrayType;
|
||||
|
||||
/**
|
||||
* Standard {@link BatchLoaderFactory} implementation
|
||||
*
|
||||
|
@ -35,23 +36,18 @@ public class StandardBatchLoaderFactory implements BatchLoaderFactory {
|
|||
public <T> EntityBatchLoader<T> createEntityBatchLoader(
|
||||
int domainBatchSize, EntityMappingType entityDescriptor,
|
||||
SessionFactoryImplementor factory) {
|
||||
final Dialect dialect = factory.getJdbcServices().getDialect();
|
||||
|
||||
// NOTE : don't use the EntityIdentifierMapping here because it will not be known until later
|
||||
final Type identifierType = entityDescriptor.getEntityPersister().getIdentifierType();
|
||||
final int idColumnCount = identifierType.getColumnSpan( factory );
|
||||
|
||||
if ( idColumnCount == 1
|
||||
&& MultiKeyLoadHelper.supportsSqlArrayType( dialect )
|
||||
if ( identifierType.getColumnSpan( factory ) == 1
|
||||
&& supportsSqlArrayType( factory.getJdbcServices().getDialect() )
|
||||
&& identifierType instanceof BasicType ) {
|
||||
// we can use a single ARRAY parameter to send all the ids
|
||||
return new EntityBatchLoaderArrayParam<>( domainBatchSize, entityDescriptor, factory );
|
||||
}
|
||||
|
||||
final int optimalBatchSize = dialect
|
||||
.getBatchLoadSizingStrategy()
|
||||
.determineOptimalBatchLoadSize( idColumnCount, domainBatchSize, false );
|
||||
return new EntityBatchLoaderInPredicate<>( domainBatchSize, optimalBatchSize, entityDescriptor, factory );
|
||||
else {
|
||||
return new EntityBatchLoaderInPredicate<>( domainBatchSize, entityDescriptor, factory );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -60,15 +56,13 @@ public class StandardBatchLoaderFactory implements BatchLoaderFactory {
|
|||
LoadQueryInfluencers influencers,
|
||||
PluralAttributeMapping attributeMapping,
|
||||
SessionFactoryImplementor factory) {
|
||||
final Dialect dialect = factory.getJdbcServices().getDialect();
|
||||
final int columnCount = attributeMapping.getKeyDescriptor().getJdbcTypeCount();
|
||||
if ( columnCount == 1
|
||||
&& dialect.supportsStandardArrays()
|
||||
&& dialect.getPreferredSqlTypeCodeForArray() == SqlTypes.ARRAY ) {
|
||||
if ( attributeMapping.getKeyDescriptor().getJdbcTypeCount() == 1
|
||||
&& supportsSqlArrayType( factory.getJdbcServices().getDialect() ) ) {
|
||||
// we can use a single ARRAY parameter to send all the ids
|
||||
return new CollectionBatchLoaderArrayParam( domainBatchSize, influencers, attributeMapping, factory );
|
||||
}
|
||||
|
||||
return new CollectionBatchLoaderInPredicate( domainBatchSize, influencers, attributeMapping, factory );
|
||||
else {
|
||||
return new CollectionBatchLoaderInPredicate( domainBatchSize, influencers, attributeMapping, factory );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,17 +30,21 @@ public interface Loadable extends ModelPart, RootTableGroupProducer {
|
|||
|
||||
default boolean isAffectedByInfluencers(LoadQueryInfluencers influencers) {
|
||||
return isAffectedByEntityGraph( influencers )
|
||||
|| isAffectedByEnabledFetchProfiles( influencers )
|
||||
|| isAffectedByEnabledFilters( influencers );
|
||||
|| isAffectedByEnabledFetchProfiles( influencers )
|
||||
|| isAffectedByEnabledFilters( influencers )
|
||||
|| influencers.getBatchSize() != getBatchSize();
|
||||
}
|
||||
|
||||
default boolean isNotAffectedByInfluencers(LoadQueryInfluencers influencers) {
|
||||
return !isAffectedByEntityGraph( influencers )
|
||||
&& !isAffectedByEnabledFetchProfiles( influencers )
|
||||
&& !isAffectedByEnabledFilters( influencers )
|
||||
&& influencers.getEnabledCascadingFetchProfile() == null;
|
||||
&& !isAffectedByEnabledFetchProfiles( influencers )
|
||||
&& !isAffectedByEnabledFilters( influencers )
|
||||
&& influencers.getBatchSize() == getBatchSize()
|
||||
&& influencers.getEnabledCascadingFetchProfile() == null;
|
||||
}
|
||||
|
||||
int getBatchSize();
|
||||
|
||||
/**
|
||||
* Whether any of the "influencers" affect this loadable.
|
||||
*/
|
||||
|
|
|
@ -885,6 +885,11 @@ public class PluralAttributeMappingImpl
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return getCollectionDescriptor().getBatchSize();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
|
||||
return getCollectionDescriptor().isAffectedByEnabledFilters( influencers );
|
||||
|
|
|
@ -6,17 +6,6 @@
|
|||
*/
|
||||
package org.hibernate.persister.collection;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.FetchMode;
|
||||
import org.hibernate.Filter;
|
||||
|
@ -27,6 +16,7 @@ import org.hibernate.MappingException;
|
|||
import org.hibernate.QueryException;
|
||||
import org.hibernate.Remove;
|
||||
import org.hibernate.TransientObjectException;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.cache.CacheException;
|
||||
import org.hibernate.cache.spi.access.CollectionDataAccess;
|
||||
import org.hibernate.cache.spi.entry.CacheEntryStructure;
|
||||
|
@ -124,7 +114,6 @@ import org.hibernate.sql.model.ast.RestrictedTableMutation;
|
|||
import org.hibernate.sql.model.internal.TableDeleteStandard;
|
||||
import org.hibernate.sql.model.jdbc.JdbcDeleteMutation;
|
||||
import org.hibernate.sql.model.jdbc.JdbcMutationOperation;
|
||||
import org.hibernate.sql.results.graph.DomainResult;
|
||||
import org.hibernate.sql.results.graph.internal.ImmutableFetchList;
|
||||
import org.hibernate.sql.results.internal.SqlSelectionImpl;
|
||||
import org.hibernate.type.CollectionType;
|
||||
|
@ -132,6 +121,17 @@ import org.hibernate.type.CompositeType;
|
|||
import org.hibernate.type.EntityType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.arrayList;
|
||||
import static org.hibernate.sql.model.ModelMutationLogging.MODEL_MUTATION_LOGGER;
|
||||
|
||||
|
@ -228,7 +228,7 @@ public abstract class AbstractCollectionPersister
|
|||
private final Comparator<?> comparator;
|
||||
|
||||
private CollectionLoader collectionLoader;
|
||||
private volatile CollectionLoader standardCollectionLoader;
|
||||
// private volatile CollectionLoader standardCollectionLoader;
|
||||
private CollectionElementLoaderByIndex collectionElementLoaderByIndex;
|
||||
|
||||
private PluralAttributeMapping attributeMapping;
|
||||
|
@ -570,14 +570,8 @@ public abstract class AbstractCollectionPersister
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// "mapping model"
|
||||
|
||||
if ( queryLoaderName != null ) {
|
||||
final NamedQueryMemento namedQueryMemento = factory
|
||||
.getQueryEngine()
|
||||
.getNamedObjectRepository()
|
||||
.resolve( factory, collectionBootDescriptor.getMetadata(), queryLoaderName );
|
||||
if ( namedQueryMemento == null ) {
|
||||
throw new IllegalArgumentException( "Could not resolve named load-query [" + navigableRole + "] : " + queryLoaderName );
|
||||
}
|
||||
if ( hasNamedQueryLoader() ) {
|
||||
getNamedQueryMemento( collectionBootDescriptor.getMetadata() );
|
||||
}
|
||||
|
||||
tableMapping = buildCollectionTableMapping( collectionBootDescriptor, getTableName(), getCollectionSpaces() );
|
||||
|
@ -614,14 +608,12 @@ public abstract class AbstractCollectionPersister
|
|||
|
||||
@Override
|
||||
public void postInstantiate() throws MappingException {
|
||||
if ( queryLoaderName == null ) {
|
||||
collectionLoader = createCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
if ( hasNamedQueryLoader() ) {
|
||||
// We pass null as metamodel because we did the initialization during construction already
|
||||
collectionLoader = new CollectionLoaderNamedQuery( this, getNamedQueryMemento( null ) );
|
||||
}
|
||||
else {
|
||||
// We pass null as metamodel because we did the initialization during construction already
|
||||
final NamedQueryMemento namedQueryMemento = factory.getQueryEngine().getNamedObjectRepository()
|
||||
.resolve( factory, null, queryLoaderName );
|
||||
collectionLoader = new CollectionLoaderNamedQuery( this, namedQueryMemento );
|
||||
collectionLoader = createCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
|
||||
if ( attributeMapping.getIndexDescriptor() != null ) {
|
||||
|
@ -635,6 +627,17 @@ public abstract class AbstractCollectionPersister
|
|||
logStaticSQL();
|
||||
}
|
||||
|
||||
private NamedQueryMemento getNamedQueryMemento(MetadataImplementor bootModel) {
|
||||
final NamedQueryMemento memento =
|
||||
factory.getQueryEngine().getNamedObjectRepository()
|
||||
.resolve( factory, bootModel, queryLoaderName );
|
||||
if ( memento == null ) {
|
||||
throw new IllegalArgumentException( "Could not resolve named query '" + queryLoaderName
|
||||
+ "' for loading collection '" + getName() + "'" );
|
||||
}
|
||||
return memento;
|
||||
}
|
||||
|
||||
protected void logStaticSQL() {
|
||||
if ( !ModelMutationLogging.MODEL_MUTATION_LOGGER_DEBUG_ENABLED ) {
|
||||
return;
|
||||
|
@ -676,51 +679,50 @@ public abstract class AbstractCollectionPersister
|
|||
|
||||
// lazily initialize instance field via 'double-checked locking'
|
||||
// see https://en.wikipedia.org/wiki/Double-checked_locking on why 'volatile' and local copy is used
|
||||
protected CollectionLoader getStandardCollectionLoader() {
|
||||
CollectionLoader localCopy = standardCollectionLoader;
|
||||
if ( localCopy == null ) {
|
||||
synchronized (this) {
|
||||
localCopy = standardCollectionLoader;
|
||||
if ( localCopy == null ) {
|
||||
if ( queryLoaderName != null ) {
|
||||
localCopy = collectionLoader;
|
||||
}
|
||||
else {
|
||||
localCopy = createCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
standardCollectionLoader = localCopy;
|
||||
}
|
||||
}
|
||||
}
|
||||
return localCopy;
|
||||
// protected CollectionLoader getStandardCollectionLoader() {
|
||||
// CollectionLoader localCopy = standardCollectionLoader;
|
||||
// if ( localCopy == null ) {
|
||||
// synchronized (this) {
|
||||
// localCopy = standardCollectionLoader;
|
||||
// if ( localCopy == null ) {
|
||||
// localCopy = createCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
// standardCollectionLoader = localCopy;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return localCopy;
|
||||
// }
|
||||
|
||||
private boolean hasNamedQueryLoader() {
|
||||
return queryLoaderName != null;
|
||||
}
|
||||
|
||||
public CollectionLoader getCollectionLoader() {
|
||||
return collectionLoader;
|
||||
}
|
||||
|
||||
protected CollectionLoader determineLoaderToUse(Object key, SharedSessionContractImplementor session) {
|
||||
if ( queryLoaderName != null ) {
|
||||
if ( hasNamedQueryLoader() ) {
|
||||
// if there is a user-specified loader, return that
|
||||
return getStandardCollectionLoader();
|
||||
return getCollectionLoader();
|
||||
}
|
||||
final LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers();
|
||||
|
||||
if ( loadQueryInfluencers.effectiveSubselectFetchEnabled( this ) ) {
|
||||
final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers();
|
||||
|
||||
if ( influencers.effectiveSubselectFetchEnabled( this ) ) {
|
||||
final CollectionLoader subSelectLoader = resolveSubSelectLoader( key, session );
|
||||
if ( subSelectLoader != null ) {
|
||||
return subSelectLoader;
|
||||
}
|
||||
}
|
||||
|
||||
if ( !loadQueryInfluencers.hasEnabledFilters()
|
||||
&& !isAffectedByEnabledFetchProfiles( loadQueryInfluencers ) ) {
|
||||
return getStandardCollectionLoader();
|
||||
}
|
||||
else {
|
||||
return createCollectionLoader( loadQueryInfluencers );
|
||||
}
|
||||
return attributeMapping.isAffectedByInfluencers( influencers )
|
||||
? createCollectionLoader( influencers )
|
||||
: getCollectionLoader();
|
||||
}
|
||||
|
||||
private CollectionLoader resolveSubSelectLoader(Object key, SharedSessionContractImplementor session) {
|
||||
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
|
||||
|
||||
final SubselectFetch subselect =
|
||||
persistenceContext.getBatchFetchQueue()
|
||||
.getSubselect( session.generateEntityKey( key, getOwnerEntityPersister() ) );
|
||||
|
@ -728,50 +730,47 @@ public abstract class AbstractCollectionPersister
|
|||
return null;
|
||||
}
|
||||
else {
|
||||
// Take care of any entities that might have
|
||||
// been evicted!
|
||||
// Remove keys of any entities that have been evicted
|
||||
subselect.getResultingEntityKeys()
|
||||
.removeIf( entityKey -> !persistenceContext.containsEntity( entityKey ) );
|
||||
|
||||
// Run a subquery loader
|
||||
return createSubSelectLoader( subselect, session );
|
||||
}
|
||||
}
|
||||
|
||||
protected CollectionLoader createSubSelectLoader(SubselectFetch subselect, SharedSessionContractImplementor session) {
|
||||
//noinspection RedundantCast
|
||||
return new CollectionLoaderSubSelectFetch( attributeMapping, (DomainResult<?>) null, subselect, session );
|
||||
return new CollectionLoaderSubSelectFetch( attributeMapping, null, subselect, session );
|
||||
}
|
||||
//
|
||||
// private CollectionLoader reusableCollectionLoader;
|
||||
//
|
||||
// protected CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
// if ( canUseReusableCollectionLoader( loadQueryInfluencers ) ) {
|
||||
// if ( reusableCollectionLoader == null ) {
|
||||
// reusableCollectionLoader = generateCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
// }
|
||||
// return reusableCollectionLoader;
|
||||
// }
|
||||
// else {
|
||||
// // create a one-off
|
||||
// return generateCollectionLoader( loadQueryInfluencers );
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// private boolean canUseReusableCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
// // we can reuse it so long as none of the enabled influencers affect it
|
||||
// return attributeMapping.isNotAffectedByInfluencers( loadQueryInfluencers );
|
||||
// }
|
||||
|
||||
private CollectionLoader reusableCollectionLoader;
|
||||
|
||||
protected CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
if ( canUseReusableCollectionLoader( loadQueryInfluencers ) ) {
|
||||
if ( reusableCollectionLoader == null ) {
|
||||
reusableCollectionLoader = generateCollectionLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
return reusableCollectionLoader;
|
||||
}
|
||||
else {
|
||||
// create a one-off
|
||||
return generateCollectionLoader( loadQueryInfluencers );
|
||||
}
|
||||
}
|
||||
|
||||
private boolean canUseReusableCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
// we can reuse it so long as none of the enabled influencers affect it
|
||||
return attributeMapping.isNotAffectedByInfluencers( loadQueryInfluencers );
|
||||
}
|
||||
|
||||
private CollectionLoader generateCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
private CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) {
|
||||
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
|
||||
return getFactory().getServiceRegistry()
|
||||
return factory.getServiceRegistry()
|
||||
.getService( BatchLoaderFactory.class )
|
||||
.createCollectionBatchLoader( batchSize, loadQueryInfluencers, attributeMapping, getFactory() );
|
||||
.createCollectionBatchLoader( batchSize, loadQueryInfluencers, attributeMapping, factory );
|
||||
}
|
||||
else {
|
||||
return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, getFactory() );
|
||||
return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, factory );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1564,16 +1563,13 @@ public abstract class AbstractCollectionPersister
|
|||
|
||||
@Override
|
||||
public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers) {
|
||||
if ( affectingFetchProfiles == null ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for ( Map.Entry<String, Fetch.Style> entry : affectingFetchProfiles.entrySet() ) {
|
||||
if ( influencers.isFetchProfileEnabled( entry.getKey() ) ) {
|
||||
return true;
|
||||
if ( affectingFetchProfiles != null && influencers.hasEnabledFetchProfiles() ) {
|
||||
for ( String profileName : affectingFetchProfiles.keySet() ) {
|
||||
if ( influencers.isFetchProfileEnabled( profileName ) ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1581,11 +1577,12 @@ public abstract class AbstractCollectionPersister
|
|||
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers) {
|
||||
if ( influencers.hasEnabledFilters() ) {
|
||||
final Map<String, Filter> enabledFilters = influencers.getEnabledFilters();
|
||||
return ( filterHelper != null && filterHelper.isAffectedBy( enabledFilters ) )
|
||||
|| ( manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters ) );
|
||||
return filterHelper != null && filterHelper.isAffectedBy( enabledFilters )
|
||||
|| manyToManyFilterHelper != null && manyToManyFilterHelper.isAffectedBy( enabledFilters );
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -44,6 +44,7 @@ import org.hibernate.Remove;
|
|||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.StaleStateException;
|
||||
import org.hibernate.boot.Metadata;
|
||||
import org.hibernate.boot.spi.MetadataImplementor;
|
||||
import org.hibernate.boot.spi.SessionFactoryOptions;
|
||||
import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer;
|
||||
import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor;
|
||||
|
@ -301,6 +302,7 @@ import static org.hibernate.internal.util.collections.ArrayHelper.toTypeArray;
|
|||
import static org.hibernate.internal.util.collections.CollectionHelper.isNotEmpty;
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.setOfSize;
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.toSmallList;
|
||||
import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.supportsSqlArrayType;
|
||||
import static org.hibernate.metamodel.RepresentationMode.POJO;
|
||||
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
|
||||
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
|
||||
|
@ -327,8 +329,8 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
private final String sqlAliasStem;
|
||||
|
||||
private final SingleIdEntityLoader<?> singleIdLoader;
|
||||
private final MultiIdEntityLoader<?> multiIdLoader;
|
||||
private SingleIdEntityLoader<?> singleIdLoader;
|
||||
private MultiIdEntityLoader<?> multiIdLoader;
|
||||
private NaturalIdLoader<?> naturalIdLoader;
|
||||
private MultiNaturalIdLoader<?> multiNaturalIdLoader;
|
||||
|
||||
|
@ -432,6 +434,8 @@ public abstract class AbstractEntityPersister
|
|||
protected AttributeMappingsMap declaredAttributeMappings = AttributeMappingsMap.builder().build();
|
||||
protected AttributeMappingsList staticFetchableList;
|
||||
|
||||
private final String queryLoaderName;
|
||||
|
||||
private BeforeExecutionGenerator versionGenerator;
|
||||
|
||||
protected ReflectionOptimizer.AccessOptimizer accessOptimizer;
|
||||
|
@ -524,22 +528,7 @@ public abstract class AbstractEntityPersister
|
|||
final String rowId = persistentClass.getRootTable().getRowId();
|
||||
rowIdName = rowId == null ? null : dialect.rowId( rowId );
|
||||
|
||||
if ( persistentClass.getLoaderName() != null ) {
|
||||
// We must resolve the named query on-demand through the boot model because it isn't initialized yet
|
||||
final NamedQueryMemento namedQueryMemento =
|
||||
factory.getQueryEngine().getNamedObjectRepository()
|
||||
.resolve( factory, creationContext.getBootModel(), persistentClass.getLoaderName() );
|
||||
if ( namedQueryMemento == null ) {
|
||||
throw new IllegalArgumentException( "Could not resolve named load-query [" + getEntityName()
|
||||
+ "] : " + persistentClass.getLoaderName() );
|
||||
}
|
||||
singleIdLoader = new SingleIdEntityLoaderProvidedQueryImpl<>( this, namedQueryMemento );
|
||||
}
|
||||
else {
|
||||
singleIdLoader = createSingleIdEntityLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
|
||||
multiIdLoader = buildMultiIdLoader( persistentClass );
|
||||
queryLoaderName = persistentClass.getLoaderName();
|
||||
|
||||
final TypeConfiguration typeConfiguration = creationContext.getTypeConfiguration();
|
||||
final SqmFunctionRegistry functionRegistry = creationContext.getFunctionRegistry();
|
||||
|
@ -805,12 +794,29 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
fullDiscriminatorSQLValues = toStringArray( sqlValues );
|
||||
fullDiscriminatorValues = toObjectArray( values );
|
||||
|
||||
if ( hasNamedQueryLoader() ) {
|
||||
getNamedQueryMemento( creationContext.getBootModel() );
|
||||
}
|
||||
}
|
||||
|
||||
private NamedQueryMemento getNamedQueryMemento(MetadataImplementor bootModel) {
|
||||
final NamedQueryMemento memento =
|
||||
factory.getQueryEngine().getNamedObjectRepository()
|
||||
.resolve( factory, bootModel, queryLoaderName );
|
||||
if ( memento == null ) {
|
||||
throw new IllegalArgumentException( "Could not resolve named query '" + queryLoaderName
|
||||
+ "' for loading entity '" + getEntityName() + "'" );
|
||||
}
|
||||
return memento;
|
||||
}
|
||||
|
||||
private SingleIdEntityLoader<?> createSingleIdEntityLoader(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) {
|
||||
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
|
||||
return createBatchingIdEntityLoader( this, batchSize, factory );
|
||||
return factory.getServiceRegistry()
|
||||
.getService( BatchLoaderFactory.class )
|
||||
.createEntityBatchLoader( batchSize, this, factory );
|
||||
}
|
||||
else {
|
||||
return new SingleIdEntityLoaderStandardImpl<>( this, factory );
|
||||
|
@ -836,12 +842,14 @@ public abstract class AbstractEntityPersister
|
|||
return entityNameByTableNameMap;
|
||||
}
|
||||
|
||||
private MultiIdEntityLoader<Object> buildMultiIdLoader(PersistentClass persistentClass) {
|
||||
if ( persistentClass.getIdentifier() instanceof BasicValue
|
||||
&& MultiKeyLoadHelper.supportsSqlArrayType( factory.getServiceRegistry().getService( JdbcServices.class ).getDialect() ) ) {
|
||||
private MultiIdEntityLoader<Object> buildMultiIdLoader() {
|
||||
if ( getIdentifierType() instanceof BasicType
|
||||
&& supportsSqlArrayType( factory.getJdbcServices().getDialect() ) ) {
|
||||
return new MultiIdEntityLoaderArrayParam<>( this, factory );
|
||||
}
|
||||
return new MultiIdEntityLoaderStandard<>( this, persistentClass, factory );
|
||||
else {
|
||||
return new MultiIdEntityLoaderStandard<>( this, identifierColumnSpan, factory );
|
||||
}
|
||||
}
|
||||
|
||||
private String getIdentitySelectString(Dialect dialect) {
|
||||
|
@ -1051,15 +1059,6 @@ public abstract class AbstractEntityPersister
|
|||
return tableNames;
|
||||
}
|
||||
|
||||
private static SingleIdEntityLoader<?> createBatchingIdEntityLoader(
|
||||
EntityMappingType entityDescriptor,
|
||||
int domainBatchSize,
|
||||
SessionFactoryImplementor factory) {
|
||||
return factory.getServiceRegistry()
|
||||
.getService( BatchLoaderFactory.class )
|
||||
.createEntityBatchLoader( domainBatchSize, entityDescriptor, factory );
|
||||
}
|
||||
|
||||
/**
|
||||
* We might need to use cache invalidation if we have formulas,
|
||||
* dynamic update, or secondary tables.
|
||||
|
@ -3390,8 +3389,28 @@ public abstract class AbstractEntityPersister
|
|||
@Override
|
||||
public final void postInstantiate() throws MappingException {
|
||||
doLateInit();
|
||||
prepareLoader( singleIdLoader );
|
||||
if ( hasNamedQueryLoader() ) {
|
||||
// We must resolve the named query on-demand through the boot model because it isn't initialized yet
|
||||
final NamedQueryMemento memento = getNamedQueryMemento( null );
|
||||
singleIdLoader = new SingleIdEntityLoaderProvidedQueryImpl<>( this, memento );
|
||||
prepareLoader( singleIdLoader );
|
||||
}
|
||||
else {
|
||||
singleIdLoader = createAndPrepareSingleIdEntityLoader( new LoadQueryInfluencers( factory ) );
|
||||
}
|
||||
multiIdLoader = buildAndPrepareMultiIdLoader();
|
||||
}
|
||||
|
||||
private MultiIdEntityLoader<Object> buildAndPrepareMultiIdLoader() {
|
||||
MultiIdEntityLoader<Object> multiIdLoader = buildMultiIdLoader();
|
||||
prepareLoader( multiIdLoader );
|
||||
return multiIdLoader;
|
||||
}
|
||||
|
||||
private SingleIdEntityLoader<?> createAndPrepareSingleIdEntityLoader(LoadQueryInfluencers influencers) {
|
||||
SingleIdEntityLoader<?> singleIdLoader = createSingleIdEntityLoader( influencers );
|
||||
prepareLoader( singleIdLoader );
|
||||
return singleIdLoader;
|
||||
}
|
||||
|
||||
private void prepareLoader(Loader loader) {
|
||||
|
@ -3430,14 +3449,29 @@ public abstract class AbstractEntityPersister
|
|||
LOG.tracev( "Fetching entity: {0}", infoString( this, id, getFactory() ) );
|
||||
}
|
||||
|
||||
if ( optionalObject == null ) {
|
||||
return singleIdLoader.load( id, lockOptions, readOnly, session );
|
||||
final SingleIdEntityLoader<?> loader = determineLoaderToUse( session );
|
||||
return optionalObject == null
|
||||
? loader.load( id, lockOptions, readOnly, session )
|
||||
: loader.load( id, optionalObject, lockOptions, readOnly, session );
|
||||
}
|
||||
|
||||
protected SingleIdEntityLoader<?> determineLoaderToUse(SharedSessionContractImplementor session) {
|
||||
if ( hasNamedQueryLoader() ) {
|
||||
return getSingleIdLoader();
|
||||
}
|
||||
else {
|
||||
return singleIdLoader.load( id, optionalObject, lockOptions, readOnly, session );
|
||||
final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers();
|
||||
// no subselect fetching for entities for now
|
||||
return isAffectedByInfluencers( influencers )
|
||||
? createAndPrepareSingleIdEntityLoader( influencers )
|
||||
: getSingleIdLoader();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean hasNamedQueryLoader() {
|
||||
return queryLoaderName != null;
|
||||
}
|
||||
|
||||
public SingleIdEntityLoader<?> getSingleIdLoader() {
|
||||
return singleIdLoader;
|
||||
}
|
||||
|
@ -3461,7 +3495,7 @@ public abstract class AbstractEntityPersister
|
|||
loaded = CacheEntityLoaderHelper.INSTANCE.loadFromSecondLevelCache( loadEvent, this, entityKey );
|
||||
}
|
||||
if ( loaded == null ) {
|
||||
loaded = singleIdLoader.load( identifier, entity, LockOptions.NONE, session );
|
||||
loaded = determineLoaderToUse( session ).load( identifier, entity, LockOptions.NONE, session );
|
||||
}
|
||||
|
||||
if ( loaded == null ) {
|
||||
|
@ -3517,7 +3551,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
@Override
|
||||
public boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
if ( affectingFetchProfileNames != null ) {
|
||||
if ( affectingFetchProfileNames != null && loadQueryInfluencers.hasEnabledFetchProfiles() ) {
|
||||
for ( String profileName : loadQueryInfluencers.getEnabledFetchProfileNames() ) {
|
||||
if ( affectingFetchProfileNames.contains( profileName ) ) {
|
||||
return true;
|
||||
|
@ -3529,7 +3563,7 @@ public abstract class AbstractEntityPersister
|
|||
|
||||
@Override
|
||||
public boolean isAffectedByEnabledFilters(LoadQueryInfluencers loadQueryInfluencers) {
|
||||
if ( loadQueryInfluencers.hasEnabledFilters() && filterHelper != null ) {
|
||||
if ( filterHelper != null && loadQueryInfluencers.hasEnabledFilters() ) {
|
||||
if ( filterHelper.isAffectedBy( loadQueryInfluencers.getEnabledFilters() ) ) {
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.function.Consumer;
|
|||
import org.hibernate.Incubating;
|
||||
import org.hibernate.cache.MutableCacheKeyBuilder;
|
||||
import org.hibernate.engine.OptimisticLockStyle;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.internal.util.IndexedConsumer;
|
||||
import org.hibernate.loader.ast.spi.MultiNaturalIdLoader;
|
||||
|
@ -728,4 +729,19 @@ public class AnonymousTupleEntityValuedModelPart
|
|||
public boolean containsTableReference(String tableExpression) {
|
||||
return ( (TableGroupProducer) delegate ).containsTableReference( tableExpression );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBatchSize() {
|
||||
return -1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAffectedByInfluencers(LoadQueryInfluencers influencers) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNotAffectedByInfluencers(LoadQueryInfluencers influencers) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue