HHH-14075 Changes to loaders and TwoPhaseLoad to allow "internal" loading to be reused by hibernate-reactive

This commit is contained in:
Gail Badner 2020-06-17 16:09:47 -07:00 committed by Sanne Grinovero
parent 18407c954b
commit 99c56527c8
12 changed files with 362 additions and 85 deletions

View File

@ -35,13 +35,13 @@ import org.hibernate.event.spi.PreLoadEventListener;
import org.hibernate.graph.spi.AttributeNodeImplementor;
import org.hibernate.graph.spi.GraphImplementor;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.FastSessionServices;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.pretty.MessageHelper;
import org.hibernate.property.access.internal.PropertyAccessStrategyBackRefImpl;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.stat.internal.StatsHelper;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.type.TypeHelper;
@ -121,18 +121,13 @@ public final class TwoPhaseLoad {
final boolean readOnly,
final SharedSessionContractImplementor session,
final PreLoadEvent preLoadEvent) {
final PersistenceContext persistenceContext = session.getPersistenceContext();
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
if ( entityEntry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to the session" );
}
final EventListenerGroup<PreLoadEventListener> listenerGroup = session
.getFactory()
.getServiceRegistry()
.getService( EventListenerRegistry.class )
.getEventListenerGroup( EventType.PRE_LOAD );
final Iterable<PreLoadEventListener> listeners = listenerGroup.listeners();
doInitializeEntity( entity, entityEntry, readOnly, session, preLoadEvent, listeners );
initializeEntity( entity, readOnly, session, preLoadEvent, listeners, EntityResolver.DEFAULT );
}
/**
@ -155,22 +150,46 @@ public final class TwoPhaseLoad {
final SharedSessionContractImplementor session,
final PreLoadEvent preLoadEvent,
final Iterable<PreLoadEventListener> preLoadEventListeners) {
initializeEntity( entity, readOnly, session, preLoadEvent, preLoadEventListeners, EntityResolver.DEFAULT );
}
/**
* Perform the second step of 2-phase load. Fully initialize the entity
* instance.
* <p/>
* After processing a JDBC result set, we "resolve" all the associations
* between the entities which were instantiated and had their state
* "hydrated" into an array
*
* @param entity The entity being loaded
* @param readOnly Is the entity being loaded as read-only
* @param session The Session
* @param preLoadEvent The (re-used) pre-load event
* @param preLoadEventListeners the pre-load event listeners
* @param entityResolver the resolver used for to-one entity associations
* (not used when an entity is a bytecode-enhanced lazy entity)
*/
public static void initializeEntity(
final Object entity,
final boolean readOnly,
final SharedSessionContractImplementor session,
final PreLoadEvent preLoadEvent,
final Iterable<PreLoadEventListener> preLoadEventListeners,
final EntityResolver entityResolver) {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityEntry entityEntry = persistenceContext.getEntry( entity );
if ( entityEntry == null ) {
throw new AssertionFailure( "possible non-threadsafe access to the session" );
}
doInitializeEntity( entity, entityEntry, readOnly, session, preLoadEvent, preLoadEventListeners );
initializeEntityEntryLoadedState( entity, entityEntry, session, entityResolver );
initializeEntityFromEntityEntryLoadedState( entity, entityEntry, readOnly, session, preLoadEvent, preLoadEventListeners );
}
private static void doInitializeEntity(
public static void initializeEntityEntryLoadedState(
final Object entity,
final EntityEntry entityEntry,
final boolean readOnly,
final SharedSessionContractImplementor session,
final PreLoadEvent preLoadEvent,
final Iterable<PreLoadEventListener> preLoadEventListeners) throws HibernateException {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityResolver entityResolver) throws HibernateException {
final EntityPersister persister = entityEntry.getPersister();
final Serializable id = entityEntry.getId();
final Object[] hydratedState = entityEntry.getLoadedState();
@ -229,18 +248,36 @@ public final class TwoPhaseLoad {
// we know value != LazyPropertyInitializer.UNFETCHED_PROPERTY
Boolean overridingEager = getOverridingEager( session, entityName, propertyNames[i], types[i], debugEnabled );
hydratedState[i] = types[i].resolve( value, session, entity, overridingEager );
hydratedState[i] = types[i].isEntityType()
? entityResolver.resolve( (EntityType) types[i], value, session, entity, overridingEager )
: types[i].resolve( value, session, entity, overridingEager );
}
else {
if ( debugEnabled ) {
LOG.debugf( "Skipping <unknown> attribute : `%s`", propertyNames[i] );
}
}
if ( session.getFetchGraphLoadContext() != fetchGraphContext ) {
session.setFetchGraphLoadContext( fetchGraphContext );
}
}
}
public static void initializeEntityFromEntityEntryLoadedState(
final Object entity,
final EntityEntry entityEntry,
final boolean readOnly,
final SharedSessionContractImplementor session,
final PreLoadEvent preLoadEvent,
final Iterable<PreLoadEventListener> preLoadEventListeners) throws HibernateException {
final PersistenceContext persistenceContext = session.getPersistenceContextInternal();
final EntityPersister persister = entityEntry.getPersister();
final Serializable id = entityEntry.getId();
final Object[] hydratedState = entityEntry.getLoadedState();
final boolean debugEnabled = LOG.isDebugEnabled();
//Must occur after resolving identifiers!
if ( session.isEventSource() ) {
@ -600,4 +637,23 @@ public final class TwoPhaseLoad {
false
);
}
/**
* Implementations determine how a to-one associations is resolved.
*
* @see #initializeEntity(Object, boolean, SharedSessionContractImplementor, PreLoadEvent, Iterable, EntityResolver)
*/
public interface EntityResolver {
Object resolve(
EntityType entityType,
Object value,
SharedSessionContractImplementor session,
Object owner,
Boolean overridingEager
);
EntityResolver DEFAULT = (entityType, value, session, owner, overridingEager) ->
entityType.resolve( value, session, owner, overridingEager );
}
}

View File

@ -986,12 +986,48 @@ public abstract class Loader {
int maxRows,
List<AfterLoadAction> afterLoadActions) throws SQLException {
final int entitySpan = getEntityPersisters().length;
final boolean createSubselects = isSubselectLoadingEnabled();
final List<EntityKey[]> subselectResultKeys = createSubselects ? new ArrayList<>() : null;
final List<Object> hydratedObjects = entitySpan == 0 ? null : new ArrayList<>( entitySpan * 10 );
final List results = getRowsFromResultSet(
rs,
queryParameters,
session,
returnProxies,
forcedResultTransformer,
maxRows,
hydratedObjects,
subselectResultKeys
);
initializeEntitiesAndCollections(
hydratedObjects,
rs,
session,
queryParameters.isReadOnly( session ),
afterLoadActions
);
if ( createSubselects ) {
createSubselects( subselectResultKeys, queryParameters, session );
}
return results;
}
protected List<Object> getRowsFromResultSet(
ResultSet rs,
QueryParameters queryParameters,
SharedSessionContractImplementor session,
boolean returnProxies,
ResultTransformer forcedResultTransformer,
int maxRows,
List<Object> hydratedObjects,
List<EntityKey[]> subselectResultKeys) throws SQLException {
final int entitySpan = getEntityPersisters().length;
final boolean createSubselects = isSubselectLoadingEnabled();
final EntityKey optionalObjectKey = getOptionalObjectKey( queryParameters, session );
final LockMode[] lockModesArray = getLockModes( queryParameters.getLockOptions() );
final boolean createSubselects = isSubselectLoadingEnabled();
final List subselectResultKeys = createSubselects ? new ArrayList() : null;
final ArrayList hydratedObjects = entitySpan == 0 ? null : new ArrayList( entitySpan * 10 );
final List results = new ArrayList();
final List<Object> results = new ArrayList<>();
handleEmptyCollections( queryParameters.getCollectionKeys(), rs, session );
EntityKey[] keys = new EntityKey[entitySpan]; //we can reuse it for each row
@ -1023,16 +1059,6 @@ public abstract class Loader {
LOG.tracev( "Done processing result set ({0} rows)", count );
initializeEntitiesAndCollections(
hydratedObjects,
rs,
session,
queryParameters.isReadOnly( session ),
afterLoadActions
);
if ( createSubselects ) {
createSubselects( subselectResultKeys, queryParameters, session );
}
return results;
}
@ -1061,7 +1087,7 @@ public abstract class Loader {
return result;
}
private void createSubselects(List keys, QueryParameters queryParameters, SharedSessionContractImplementor session) {
protected void createSubselects(List keys, QueryParameters queryParameters, SharedSessionContractImplementor session) {
if ( keys.size() > 1 ) { //if we only returned one entity, query by key is more efficient
Set[] keySets = transpose( keys );

View File

@ -62,7 +62,7 @@ public abstract class OuterJoinLoader extends BasicLoader {
return sql;
}
protected final Loadable[] getEntityPersisters() {
public final Loadable[] getEntityPersisters() {
return persisters;
}
@ -90,7 +90,7 @@ public abstract class OuterJoinLoader extends BasicLoader {
return aliases;
}
protected final CollectionPersister[] getCollectionPersisters() {
public final CollectionPersister[] getCollectionPersisters() {
return collectionPersisters;
}

View File

@ -31,6 +31,7 @@ import org.hibernate.loader.plan.build.spi.MetamodelDrivenLoadPlanBuilder;
import org.hibernate.loader.plan.exec.internal.AbstractLoadPlanBasedLoader;
import org.hibernate.loader.plan.exec.internal.BatchingLoadQueryDetailsFactory;
import org.hibernate.loader.plan.exec.internal.EntityLoadQueryDetails;
import org.hibernate.loader.plan.exec.process.spi.ResultSetProcessorResolver;
import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters;
import org.hibernate.loader.plan.exec.spi.LoadQueryDetails;
import org.hibernate.loader.plan.spi.LoadPlan;
@ -58,7 +59,8 @@ public abstract class AbstractLoadPlanBasedEntityLoader extends AbstractLoadPlan
SessionFactoryImplementor factory,
String[] uniqueKeyColumnNames,
Type uniqueKeyType,
QueryBuildingParameters buildingParameters) {
QueryBuildingParameters buildingParameters,
ResultSetProcessorResolver resultSetProcessorResolver) {
super( factory );
this.entityPersister = entityPersister;
this.uniqueKeyType = uniqueKeyType;
@ -96,7 +98,42 @@ public abstract class AbstractLoadPlanBasedEntityLoader extends AbstractLoadPlan
plan,
uniqueKeyColumnNames,
buildingParameters,
factory
factory,
resultSetProcessorResolver
);
}
public AbstractLoadPlanBasedEntityLoader(
OuterJoinLoadable entityPersister,
SessionFactoryImplementor factory,
String[] uniqueKeyColumnNames,
Type uniqueKeyType,
QueryBuildingParameters buildingParameters) {
this(
entityPersister,
factory,
uniqueKeyColumnNames,
uniqueKeyType,
buildingParameters,ResultSetProcessorResolver.DEFAULT
);
}
protected AbstractLoadPlanBasedEntityLoader(
OuterJoinLoadable entityPersister,
SessionFactoryImplementor factory,
EntityLoadQueryDetails entityLoaderQueryDetailsTemplate,
Type uniqueKeyType,
QueryBuildingParameters buildingParameters,
ResultSetProcessorResolver resultSetProcessorResolver) {
super( factory );
this.entityPersister = entityPersister;
this.uniqueKeyType = uniqueKeyType;
this.entityName = entityPersister.getEntityName();
this.staticLoadQuery = BatchingLoadQueryDetailsFactory.INSTANCE.makeEntityLoadQueryDetails(
entityLoaderQueryDetailsTemplate,
buildingParameters,
resultSetProcessorResolver
);
}
@ -106,14 +143,13 @@ public abstract class AbstractLoadPlanBasedEntityLoader extends AbstractLoadPlan
EntityLoadQueryDetails entityLoaderQueryDetailsTemplate,
Type uniqueKeyType,
QueryBuildingParameters buildingParameters) {
super( factory );
this.entityPersister = entityPersister;
this.uniqueKeyType = uniqueKeyType;
this.entityName = entityPersister.getEntityName();
this.staticLoadQuery = BatchingLoadQueryDetailsFactory.INSTANCE.makeEntityLoadQueryDetails(
this(
entityPersister,
factory,
entityLoaderQueryDetailsTemplate,
buildingParameters
uniqueKeyType,
buildingParameters,
ResultSetProcessorResolver.DEFAULT
);
}

View File

@ -17,6 +17,7 @@ import org.hibernate.loader.plan.exec.process.spi.CollectionReferenceInitializer
import org.hibernate.loader.plan.exec.process.spi.EntityReferenceInitializer;
import org.hibernate.loader.plan.exec.process.spi.ReaderCollector;
import org.hibernate.loader.plan.exec.process.spi.ResultSetProcessor;
import org.hibernate.loader.plan.exec.process.spi.ResultSetProcessorResolver;
import org.hibernate.loader.plan.exec.query.internal.SelectStatementBuilder;
import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters;
import org.hibernate.loader.plan.exec.spi.AliasResolutionContext;
@ -104,6 +105,10 @@ public abstract class AbstractLoadQueryDetails implements LoadQueryDetails {
*
*/
protected void generate() {
generate( ResultSetProcessorResolver.DEFAULT );
}
protected void generate(ResultSetProcessorResolver resultSetProcessorResolver) {
// There are 2 high-level requirements to perform here:
// 1) Determine the SQL required to carry out the given LoadPlan (and fulfill
// {@code LoadQueryDetails#getSqlStatement()}). SelectStatementBuilder collects the ongoing efforts to
@ -190,10 +195,10 @@ public abstract class AbstractLoadQueryDetails implements LoadQueryDetails {
LoadPlanTreePrinter.INSTANCE.logTree( loadPlan, queryProcessor.getAliasResolutionContext() );
this.sqlStatement = select.toStatementString();
this.resultSetProcessor = new ResultSetProcessorImpl(
this.resultSetProcessor = resultSetProcessorResolver.resolveResultSetProcessor(
loadPlan,
queryProcessor.getAliasResolutionContext(),
getReaderCollector().buildRowReader(),
getReaderCollector(),
shouldUseOptionalEntityInstance(),
isSubselectLoadingEnabled( fetchStats )
);

View File

@ -7,6 +7,7 @@
package org.hibernate.loader.plan.exec.internal;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.loader.plan.exec.process.spi.ResultSetProcessorResolver;
import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters;
import org.hibernate.loader.plan.exec.spi.LoadQueryDetails;
import org.hibernate.loader.plan.spi.CollectionReturn;
@ -38,6 +39,7 @@ public class BatchingLoadQueryDetailsFactory {
* @param buildingParameters Any influencers that would affect the generated SQL (mostly we are concerned with those
* that add additional joins here)
* @param factory The SessionFactory
* @oaram resultSetProcessorResolver The ResultSet processor resolver.
*
* @return The EntityLoadQueryDetails
*/
@ -45,7 +47,8 @@ public class BatchingLoadQueryDetailsFactory {
LoadPlan loadPlan,
String[] keyColumnNames,
QueryBuildingParameters buildingParameters,
SessionFactoryImplementor factory) {
SessionFactoryImplementor factory,
ResultSetProcessorResolver resultSetProcessorResolver) {
// TODO: how should shouldUseOptionalEntityInformation be used?
// final int batchSize = buildingParameters.getBatchSize();
@ -64,7 +67,54 @@ public class BatchingLoadQueryDetailsFactory {
aliasResolutionContext,
rootReturn,
buildingParameters,
factory
factory,
resultSetProcessorResolver
);
}
/**
* Returns an EntityLoadQueryDetails object from the given inputs.
*
* @param loadPlan The load plan
* @param keyColumnNames The columns to load the entity by (the PK columns or some other unique set of columns)
* @param buildingParameters Any influencers that would affect the generated SQL (mostly we are concerned with those
* that add additional joins here)
* @param factory The SessionFactory
*
* @return The EntityLoadQueryDetails
*/
public EntityLoadQueryDetails makeEntityLoadQueryDetails(
LoadPlan loadPlan,
String[] keyColumnNames,
QueryBuildingParameters buildingParameters,
SessionFactoryImplementor factory) {
return makeEntityLoadQueryDetails(
loadPlan,
keyColumnNames,
buildingParameters,
factory,
ResultSetProcessorResolver.DEFAULT
);
}
/**
* Returns a EntityLoadQueryDetails object based on an existing one and additional elements specific to this one.
*
* @param entityLoadQueryDetailsTemplate the template
* @param buildingParameters Any influencers that would affect the generated SQL (mostly we are concerned with those
* that add additional joins here)
* @oaram resultSetProcessorResolver The ResultSet processor resolver.
*
* @return The EntityLoadQueryDetails
*/
public EntityLoadQueryDetails makeEntityLoadQueryDetails(
EntityLoadQueryDetails entityLoadQueryDetailsTemplate,
QueryBuildingParameters buildingParameters,
ResultSetProcessorResolver resultSetProcessorResolver) {
return new EntityLoadQueryDetails(
entityLoadQueryDetailsTemplate,
buildingParameters,
resultSetProcessorResolver
);
}
@ -79,9 +129,10 @@ public class BatchingLoadQueryDetailsFactory {
public EntityLoadQueryDetails makeEntityLoadQueryDetails(
EntityLoadQueryDetails entityLoadQueryDetailsTemplate,
QueryBuildingParameters buildingParameters) {
return new EntityLoadQueryDetails(
return makeEntityLoadQueryDetails(
entityLoadQueryDetailsTemplate,
buildingParameters
buildingParameters,
ResultSetProcessorResolver.DEFAULT
);
}

View File

@ -22,6 +22,7 @@ import org.hibernate.loader.plan.exec.process.internal.ResultSetProcessingContex
import org.hibernate.loader.plan.exec.process.spi.EntityReferenceInitializer;
import org.hibernate.loader.plan.exec.process.spi.ReaderCollector;
import org.hibernate.loader.plan.exec.process.spi.ResultSetProcessingContext;
import org.hibernate.loader.plan.exec.process.spi.ResultSetProcessorResolver;
import org.hibernate.loader.plan.exec.process.spi.RowReader;
import org.hibernate.loader.plan.exec.query.internal.SelectStatementBuilder;
import org.hibernate.loader.plan.exec.query.spi.QueryBuildingParameters;
@ -58,6 +59,7 @@ public class EntityLoadQueryDetails extends AbstractLoadQueryDetails {
* @param buildingParameters Any influencers that would affect the generated SQL (mostly we are concerned with those
* that add additional joins here)
* @param factory The SessionFactory
* @param resultSetProcessorResolver The ResultSet resolver.
*/
protected EntityLoadQueryDetails(
LoadPlan loadPlan,
@ -65,7 +67,9 @@ public class EntityLoadQueryDetails extends AbstractLoadQueryDetails {
AliasResolutionContextImpl aliasResolutionContext,
EntityReturn rootReturn,
QueryBuildingParameters buildingParameters,
SessionFactoryImplementor factory) {
SessionFactoryImplementor factory,
ResultSetProcessorResolver resultSetProcessorResolver) {
super(
loadPlan,
aliasResolutionContext,
@ -82,21 +86,55 @@ public class EntityLoadQueryDetails extends AbstractLoadQueryDetails {
new EntityReturnReader( rootReturn ),
new EntityReferenceInitializerImpl( rootReturn, entityReferenceAliases, true )
);
generate();
generate( resultSetProcessorResolver );
}
/**
* Constructs a EntityLoadQueryDetails object from the given inputs.
*
* @param loadPlan The load plan
* @param keyColumnNames The columns to load the entity by (the PK columns or some other unique set of columns)
* @param buildingParameters Any influencers that would affect the generated SQL (mostly we are concerned with those
* that add additional joins here)
* @param factory The SessionFactory
*/
protected EntityLoadQueryDetails(
LoadPlan loadPlan,
String[] keyColumnNames,
AliasResolutionContextImpl aliasResolutionContext,
EntityReturn rootReturn,
QueryBuildingParameters buildingParameters,
SessionFactoryImplementor factory) {
this(
loadPlan,
keyColumnNames,
aliasResolutionContext,
rootReturn,
buildingParameters,
factory,
ResultSetProcessorResolver.DEFAULT
);
}
protected EntityLoadQueryDetails(
EntityLoadQueryDetails initialEntityLoadQueryDetails,
QueryBuildingParameters buildingParameters) {
QueryBuildingParameters buildingParameters,
ResultSetProcessorResolver resultSetProcessorResolver) {
this(
initialEntityLoadQueryDetails.getLoadPlan(),
initialEntityLoadQueryDetails.getKeyColumnNames(),
new AliasResolutionContextImpl( initialEntityLoadQueryDetails.getSessionFactory() ),
(EntityReturn) initialEntityLoadQueryDetails.getRootReturn(),
buildingParameters,
initialEntityLoadQueryDetails.getSessionFactory()
initialEntityLoadQueryDetails.getSessionFactory(),
resultSetProcessorResolver
);
}
protected EntityLoadQueryDetails(
EntityLoadQueryDetails initialEntityLoadQueryDetails,
QueryBuildingParameters buildingParameters) {
this( initialEntityLoadQueryDetails, buildingParameters, ResultSetProcessorResolver.DEFAULT );
}
public boolean hasCollectionInitializers() {
return CollectionHelper.isNotEmpty( readerCollector.getArrayReferenceInitializers() ) ||

View File

@ -224,7 +224,7 @@ public abstract class AbstractRowReader implements RowReader {
postLoad( postLoadEvent, context, hydratedEntityRegistrations, afterLoadActionList );
}
private void finishLoadingArrays(ResultSetProcessingContextImpl context) {
protected void finishLoadingArrays(ResultSetProcessingContextImpl context) {
for ( CollectionReferenceInitializer arrayReferenceInitializer : arrayReferenceInitializers ) {
arrayReferenceInitializer.endLoading( context );
}
@ -262,13 +262,13 @@ public abstract class AbstractRowReader implements RowReader {
}
}
private void finishLoadingCollections(ResultSetProcessingContextImpl context) {
protected void finishLoadingCollections(ResultSetProcessingContextImpl context) {
for ( CollectionReferenceInitializer collectionReferenceInitializer : collectionReferenceInitializers ) {
collectionReferenceInitializer.endLoading( context );
}
}
private void afterInitialize(ResultSetProcessingContextImpl context,
protected void afterInitialize(ResultSetProcessingContextImpl context,
List<HydratedEntityRegistration> hydratedEntityRegistrations) {
if ( hydratedEntityRegistrations == null ) {
return;
@ -279,7 +279,7 @@ public abstract class AbstractRowReader implements RowReader {
}
}
private void postLoad(
protected void postLoad(
PostLoadEvent postLoadEvent,
ResultSetProcessingContextImpl context,
List<HydratedEntityRegistration> hydratedEntityRegistrations,

View File

@ -315,10 +315,7 @@ public class ResultSetProcessingContextImpl implements ResultSetProcessingContex
return hydratedEntityRegistrationList;
}
/**
* Package-protected
*/
void wrapUp() {
public void wrapUp() {
createSubselects();
if ( hydratedEntityRegistrationList != null ) {

View File

@ -80,11 +80,57 @@ public class ResultSetProcessorImpl implements ResultSetProcessor {
ResultTransformer forcedResultTransformer,
List<AfterLoadAction> afterLoadActionList) throws SQLException {
handlePotentiallyEmptyCollectionRootReturns( loadPlan, queryParameters.getCollectionKeys(), resultSet, session );
handlePotentiallyEmptyCollectionRootReturns( queryParameters.getCollectionKeys(), resultSet, session );
final ResultSetProcessingContextImpl context = createResultSetProcessingContext(
resultSet,
session,
queryParameters,
namedParameterContext,
returnProxies,
readOnly
);
final List loadResults = extractRows( resultSet, queryParameters, context );
rowReader.finishUp( context, afterLoadActionList );
context.wrapUp();
session.getPersistenceContextInternal().initializeNonLazyCollections();
return loadResults;
}
protected ResultSetProcessingContextImpl createResultSetProcessingContext(
ResultSet resultSet,
final SharedSessionContractImplementor session,
QueryParameters queryParameters,
NamedParameterContext namedParameterContext,
boolean returnProxies,
boolean readOnly) {
return new ResultSetProcessingContextImpl(
resultSet,
session,
loadPlan,
aliasResolutionContext,
readOnly,
shouldUseOptionalEntityInstance,
returnProxies,
queryParameters,
namedParameterContext,
hadSubselectFetches
);
}
protected List<Object> extractRows(
ResultSet resultSet,
QueryParameters queryParameters,
final ResultSetProcessingContextImpl context) throws SQLException {
final boolean traceEnabled = LOG.isTraceEnabled();
final int maxRows;
final List loadResults;
final List<Object> loadResults;
final RowSelection selection = queryParameters.getRowSelection();
if ( LimitHelper.hasMaxRows( selection ) ) {
maxRows = selection.getMaxRows();
@ -99,19 +145,6 @@ public class ResultSetProcessorImpl implements ResultSetProcessor {
maxRows = Integer.MAX_VALUE;
}
final ResultSetProcessingContextImpl context = new ResultSetProcessingContextImpl(
resultSet,
session,
loadPlan,
aliasResolutionContext,
readOnly,
shouldUseOptionalEntityInstance,
returnProxies,
queryParameters,
namedParameterContext,
hadSubselectFetches
);
if ( traceEnabled ) {
LOG.trace( "Processing result set" );
}
@ -134,17 +167,10 @@ public class ResultSetProcessorImpl implements ResultSetProcessor {
LOG.tracev( "Done processing result set ({0} rows)", count );
}
rowReader.finishUp( context, afterLoadActionList );
context.wrapUp();
session.getPersistenceContextInternal().initializeNonLazyCollections();
return loadResults;
}
private void handlePotentiallyEmptyCollectionRootReturns(
LoadPlan loadPlan,
protected void handlePotentiallyEmptyCollectionRootReturns(
Serializable[] collectionKeys,
ResultSet resultSet,
SharedSessionContractImplementor session) {

View File

@ -0,0 +1,32 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.loader.plan.exec.process.spi;
import org.hibernate.loader.plan.exec.process.internal.ResultSetProcessorImpl;
import org.hibernate.loader.plan.exec.spi.AliasResolutionContext;
import org.hibernate.loader.plan.spi.LoadPlan;
public interface ResultSetProcessorResolver {
ResultSetProcessor resolveResultSetProcessor(
LoadPlan loadPlan,
AliasResolutionContext aliasResolutionContext,
ReaderCollector readerCollector,
boolean shouldUseOptionalEntityInstance,
boolean hadSubselectFetches
);
ResultSetProcessorResolver DEFAULT =
(loadPlan, aliasResolutionContext, readerCollector, shouldUseOptionalEntityInstance, hadSubselectFetches) ->
new ResultSetProcessorImpl(
loadPlan,
aliasResolutionContext,
readerCollector.buildRowReader(),
shouldUseOptionalEntityInstance,
hadSubselectFetches
);
}

View File

@ -471,6 +471,18 @@ public abstract class EntityType extends AbstractType implements AssociationType
return null;
}
/**
* Would an entity be eagerly loaded given the value provided for {@code overridingEager}?
*
* @param overridingEager can override eager from the mapping.
*
* @return If {@code overridingEager} is null, then it does not override.
* If true or false then it overrides the mapping value.
*/
public boolean isEager(Boolean overridingEager) {
return overridingEager != null ? overridingEager : this.eager;
}
@Override
public Type getSemiResolvedType(SessionFactoryImplementor factory) {
return getAssociatedEntityPersister( factory ).getIdentifierType();
@ -682,12 +694,10 @@ public abstract class EntityType extends AbstractType implements AssociationType
getAssociatedEntityPersister( session.getFactory() )
.isInstrumented();
boolean eager = overridingEager != null ? overridingEager : this.eager;
Object proxyOrEntity = session.internalLoad(
getAssociatedEntityName(),
id,
eager,
isEager( overridingEager ),
isNullable()
);