HHH-17037 Changes for Hibernate Reactive

Make it possible to override the SingleIdLoadPlan
and the SingleIdEntityLoader.
This commit is contained in:
Davide D'Alto 2023-08-07 10:15:53 +02:00 committed by Davide D'Alto
parent 000e21dad5
commit df88fd15fa
3 changed files with 68 additions and 39 deletions

View File

@ -7,6 +7,7 @@
package org.hibernate.loader.ast.internal;
import java.util.EnumMap;
import java.util.function.BiFunction;
import org.hibernate.Internal;
import org.hibernate.LockMode;
@ -29,20 +30,36 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
private final EnumMap<LockMode, SingleIdLoadPlan<T>> selectByLockMode = new EnumMap<>( LockMode.class );
private EnumMap<CascadingFetchProfile, SingleIdLoadPlan<T>> selectByInternalCascadeProfile;
private final BiFunction<LockOptions, LoadQueryInfluencers, SingleIdLoadPlan<T>> loadPlanCreator;
public SingleIdEntityLoaderStandardImpl(
EntityMappingType entityDescriptor,
SessionFactoryImplementor sessionFactory) {
this(
entityDescriptor,
sessionFactory,
(lockOptions, influencers) -> createLoadPlan( entityDescriptor, lockOptions, influencers, sessionFactory )
);
}
/**
* For Hibernate Reactive.
* <p>
* Hibernate Reactive needs to be able to override the LoadPlan.
* </p>
*/
protected SingleIdEntityLoaderStandardImpl(
EntityMappingType entityDescriptor,
SessionFactoryImplementor sessionFactory,
BiFunction<LockOptions, LoadQueryInfluencers, SingleIdLoadPlan<T>> loadPlanCreator) {
// todo (6.0) : consider creating a base AST and "cloning" it
super( entityDescriptor, sessionFactory );
this.loadPlanCreator = loadPlanCreator;
// see org.hibernate.persister.entity.AbstractEntityPersister#createLoaders
// we should preload a few - maybe LockMode.NONE and LockMode.READ
final LockOptions lockOptions = LockOptions.NONE;
final LoadQueryInfluencers influencers = new LoadQueryInfluencers( sessionFactory );
final SingleIdLoadPlan<T> plan = createLoadPlan(
lockOptions,
influencers,
sessionFactory
);
final SingleIdLoadPlan<T> plan = loadPlanCreator.apply( LockOptions.NONE, influencers );
if ( isLoadPlanReusable( lockOptions, influencers ) ) {
selectByLockMode.put( lockOptions.getLockMode(), plan );
}
@ -83,7 +100,7 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
// This case is special because the filters need to be applied in order to
// properly restrict the SQL/JDBC results. For this reason it has higher
// precedence than even "internal" fetch profiles.
return createLoadPlan( lockOptions, loadQueryInfluencers, sessionFactory );
return loadPlanCreator.apply( lockOptions, loadQueryInfluencers );
}
else if ( loadQueryInfluencers.hasEnabledCascadingFetchProfile()
&& LockMode.WRITE.greaterThan( lockOptions.getLockMode() ) ) {
@ -115,17 +132,13 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
return existing;
}
else {
final SingleIdLoadPlan<T> plan = createLoadPlan(
lockOptions,
loadQueryInfluencers,
sessionFactory
);
final SingleIdLoadPlan<T> plan = loadPlanCreator.apply( lockOptions, loadQueryInfluencers );
selectByLockMode.put( lockOptions.getLockMode(), plan );
return plan;
}
}
else {
return createLoadPlan( lockOptions, loadQueryInfluencers, sessionFactory );
return loadPlanCreator.apply( lockOptions, loadQueryInfluencers );
}
}
@ -148,11 +161,7 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
}
}
final SingleIdLoadPlan<T> plan = createLoadPlan(
lockOptions,
loadQueryInfluencers,
sessionFactory
);
final SingleIdLoadPlan<T> plan = loadPlanCreator.apply( lockOptions, loadQueryInfluencers );
selectByInternalCascadeProfile.put( fetchProfile, plan );
return plan;
}
@ -163,17 +172,18 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
&& !getLoadable().isAffectedByEnabledFetchProfiles( loadQueryInfluencers );
}
private SingleIdLoadPlan<T> createLoadPlan(
private static <T> SingleIdLoadPlan<T> createLoadPlan(
EntityMappingType loadable,
LockOptions lockOptions,
LoadQueryInfluencers queryInfluencers,
SessionFactoryImplementor sessionFactory) {
final JdbcParametersList.Builder jdbcParametersBuilder = JdbcParametersList.newBuilder();
final SelectStatement sqlAst = LoaderSelectBuilder.createSelect(
getLoadable(),
loadable,
// null here means to select everything
null,
getLoadable().getIdentifierMapping(),
loadable.getIdentifierMapping(),
null,
1,
queryInfluencers,
@ -182,8 +192,8 @@ public class SingleIdEntityLoaderStandardImpl<T> extends SingleIdEntityLoaderSup
sessionFactory
);
return new SingleIdLoadPlan<>(
getLoadable(),
getLoadable().getIdentifierMapping(),
loadable,
loadable.getIdentifierMapping(),
sqlAst,
jdbcParametersBuilder.build(),
lockOptions,

View File

@ -613,10 +613,10 @@ public abstract class AbstractCollectionPersister
public void postInstantiate() throws MappingException {
if ( hasNamedQueryLoader() ) {
// We pass null as metamodel because we did the initialization during construction already
collectionLoader = new CollectionLoaderNamedQuery( this, getNamedQueryMemento( null ) );
collectionLoader = createNamedQueryCollectionLoader( this, getNamedQueryMemento( null ) );
}
else {
collectionLoader = createCollectionLoader( new LoadQueryInfluencers( factory ) );
collectionLoader = createNamedQueryCollectionLoader( new LoadQueryInfluencers( factory ) );
}
if ( attributeMapping.getIndexDescriptor() != null ) {
@ -720,7 +720,7 @@ public abstract class AbstractCollectionPersister
}
return attributeMapping.isAffectedByInfluencers( influencers )
? createCollectionLoader( influencers )
? createNamedQueryCollectionLoader( influencers )
: getCollectionLoader();
}
@ -765,7 +765,7 @@ public abstract class AbstractCollectionPersister
// return attributeMapping.isNotAffectedByInfluencers( loadQueryInfluencers );
// }
private CollectionLoader createCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
private CollectionLoader createNamedQueryCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) {
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
return factory.getServiceRegistry()
@ -773,10 +773,24 @@ public abstract class AbstractCollectionPersister
.createCollectionBatchLoader( batchSize, loadQueryInfluencers, attributeMapping, factory );
}
else {
return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, factory );
return createSingleKeyCollectionLoader( loadQueryInfluencers );
}
}
/**
* For Hibernate Reactive
*/
protected CollectionLoader createNamedQueryCollectionLoader(CollectionPersister persister, NamedQueryMemento namedQueryMemento) {
return new CollectionLoaderNamedQuery(persister, namedQueryMemento);
}
/**
* For Hibernate Reactive
*/
protected CollectionLoader createSingleKeyCollectionLoader(LoadQueryInfluencers loadQueryInfluencers) {
return new CollectionLoaderSingleKey( attributeMapping, loadQueryInfluencers, factory );
}
@Override
public CollectionDataAccess getCacheAccessStrategy() {
return cacheAccessStrategy;

View File

@ -78,7 +78,6 @@ import org.hibernate.engine.internal.MutableEntityEntryFactory;
import org.hibernate.engine.internal.StatefulPersistenceContext;
import org.hibernate.engine.jdbc.mutation.spi.MutationExecutorService;
import org.hibernate.engine.jdbc.spi.JdbcCoordinator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.profile.internal.FetchProfileAffectee;
import org.hibernate.engine.spi.CachedNaturalIdValueSource;
import org.hibernate.engine.spi.CascadeStyle;
@ -831,7 +830,19 @@ public abstract class AbstractEntityPersister
return memento;
}
private SingleIdEntityLoader<?> createSingleIdEntityLoader(LoadQueryInfluencers loadQueryInfluencers) {
/**
* For Hibernate Reactive
*/
protected SingleIdEntityLoader<?> buildSingleIdEntityLoader() {
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 );
return new SingleIdEntityLoaderProvidedQueryImpl<>( this, memento );
}
return buildSingleIdEntityLoader( new LoadQueryInfluencers( factory ) );
}
private SingleIdEntityLoader<?> buildSingleIdEntityLoader(LoadQueryInfluencers loadQueryInfluencers) {
if ( loadQueryInfluencers.effectivelyBatchLoadable( this ) ) {
final int batchSize = loadQueryInfluencers.effectiveBatchSize( this );
return factory.getServiceRegistry()
@ -864,7 +875,7 @@ public abstract class AbstractEntityPersister
return entityNameByTableNameMap;
}
private MultiIdEntityLoader<Object> buildMultiIdLoader() {
protected MultiIdEntityLoader<Object> buildMultiIdLoader() {
if ( getIdentifierType() instanceof BasicType
&& supportsSqlArrayType( factory.getJdbcServices().getDialect() ) ) {
return new MultiIdEntityLoaderArrayParam<>( this, factory );
@ -3588,14 +3599,8 @@ public abstract class AbstractEntityPersister
@Override
public final void postInstantiate() throws MappingException {
doLateInit();
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 );
}
else {
singleIdLoader = createSingleIdEntityLoader( new LoadQueryInfluencers( factory ) );
}
// Hibernate Reactive needs to override the loaders
singleIdLoader = buildSingleIdEntityLoader();
multiIdLoader = buildMultiIdLoader();
}
@ -3644,7 +3649,7 @@ public abstract class AbstractEntityPersister
final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers();
// no subselect fetching for entities for now
return isAffectedByInfluencers( influencers )
? createSingleIdEntityLoader( influencers )
? buildSingleIdEntityLoader( influencers )
: getSingleIdLoader();
}
}