HHH-17948 make findAll() accept FindOptions
and add missing options to MultiIdentifierLoadAccess
This commit is contained in:
parent
62e1b0470e
commit
6e2ed7f1a0
|
@ -51,6 +51,15 @@ public interface MultiIdentifierLoadAccess<T> {
|
||||||
*/
|
*/
|
||||||
MultiIdentifierLoadAccess<T> with(CacheMode cacheMode);
|
MultiIdentifierLoadAccess<T> with(CacheMode cacheMode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specify whether the entities should be loaded in read-only mode.
|
||||||
|
*
|
||||||
|
* @see Session#setDefaultReadOnly(boolean)
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
MultiIdentifierLoadAccess<T> withReadOnly(boolean readOnly);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Override the associations fetched by default by specifying
|
* Override the associations fetched by default by specifying
|
||||||
* the complete list of associations to be fetched as an
|
* the complete list of associations to be fetched as an
|
||||||
|
@ -88,6 +97,30 @@ public interface MultiIdentifierLoadAccess<T> {
|
||||||
*/
|
*/
|
||||||
MultiIdentifierLoadAccess<T> with(RootGraph<T> graph, GraphSemantic semantic);
|
MultiIdentifierLoadAccess<T> with(RootGraph<T> graph, GraphSemantic semantic);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customize the associations fetched by specifying a
|
||||||
|
* {@linkplain org.hibernate.annotations.FetchProfile fetch profile}
|
||||||
|
* that should be enabled during this operation.
|
||||||
|
* <p>
|
||||||
|
* This allows the {@linkplain Session#isFetchProfileEnabled(String)
|
||||||
|
* session-level fetch profiles} to be temporarily overridden.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
MultiIdentifierLoadAccess<T> enableFetchProfile(String profileName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Customize the associations fetched by specifying a
|
||||||
|
* {@linkplain org.hibernate.annotations.FetchProfile fetch profile}
|
||||||
|
* that should be disabled during this operation.
|
||||||
|
* <p>
|
||||||
|
* This allows the {@linkplain Session#isFetchProfileEnabled(String)
|
||||||
|
* session-level fetch profiles} to be temporarily overridden.
|
||||||
|
*
|
||||||
|
* @since 7.0
|
||||||
|
*/
|
||||||
|
MultiIdentifierLoadAccess<T> disableFetchProfile(String profileName);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify a batch size, that is, how many entities should be
|
* Specify a batch size, that is, how many entities should be
|
||||||
* fetched in each request to the database.
|
* fetched in each request to the database.
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
import jakarta.persistence.FindOption;
|
||||||
import org.hibernate.graph.RootGraph;
|
import org.hibernate.graph.RootGraph;
|
||||||
import org.hibernate.jdbc.Work;
|
import org.hibernate.jdbc.Work;
|
||||||
import org.hibernate.query.Query;
|
import org.hibernate.query.Query;
|
||||||
|
@ -706,12 +707,13 @@ public interface Session extends SharedSessionContract, EntityManager {
|
||||||
*
|
*
|
||||||
* @param entityType the entity type
|
* @param entityType the entity type
|
||||||
* @param ids the identifiers
|
* @param ids the identifiers
|
||||||
|
* @param options options, if any
|
||||||
* @return an ordered list of persistent instances, with null elements representing missing
|
* @return an ordered list of persistent instances, with null elements representing missing
|
||||||
* entities
|
* entities
|
||||||
* @see #byMultipleIds(Class)
|
* @see #byMultipleIds(Class)
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
<E> List<E> findAll(Class<E> entityType, List<Object> ids);
|
<E> List<E> findAll(Class<E> entityType, List<Object> ids, FindOption... options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the persistent instance of the given entity class with the given identifier,
|
* Return the persistent instance of the given entity class with the given identifier,
|
||||||
|
@ -922,7 +924,7 @@ public interface Session extends SharedSessionContract, EntityManager {
|
||||||
*
|
*
|
||||||
* @throws HibernateException If the given class does not resolve as a mapped entity
|
* @throws HibernateException If the given class does not resolve as a mapped entity
|
||||||
*
|
*
|
||||||
* @see #findAll(Class, List)
|
* @see #findAll(Class, List, FindOption...)
|
||||||
*/
|
*/
|
||||||
<T> MultiIdentifierLoadAccess<T> byMultipleIds(Class<T> entityClass);
|
<T> MultiIdentifierLoadAccess<T> byMultipleIds(Class<T> entityClass);
|
||||||
|
|
||||||
|
|
|
@ -262,7 +262,7 @@ public interface StatelessSession extends SharedSessionContract {
|
||||||
* @param entityClass The class of the entity to retrieve
|
* @param entityClass The class of the entity to retrieve
|
||||||
* @param ids The ids of the entities to retrieve
|
* @param ids The ids of the entities to retrieve
|
||||||
* @return an ordered list of detached entity instances, with
|
* @return an ordered list of detached entity instances, with
|
||||||
* null elements representing missing entities
|
* null elements representing missing entities
|
||||||
* @since 7.0
|
* @since 7.0
|
||||||
*/
|
*/
|
||||||
<T> List<T> getAll(Class<T> entityClass, List<Object> ids);
|
<T> List<T> getAll(Class<T> entityClass, List<Object> ids);
|
||||||
|
|
|
@ -954,8 +954,8 @@ public class SessionDelegatorBaseImpl implements SessionImplementor {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <E> List<E> findAll(Class<E> entityType, List<Object> ids) {
|
public <E> List<E> findAll(Class<E> entityType, List<Object> ids, FindOption... options) {
|
||||||
return delegate.findAll( entityType, ids );
|
return delegate.findAll( entityType, ids, options );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -264,8 +264,8 @@ public class SessionLazyDelegator implements Session {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <E> List<E> findAll(Class<E> entityType, List<Object> ids) {
|
public <E> List<E> findAll(Class<E> entityType, List<Object> ids, FindOption... options) {
|
||||||
return this.lazySession.get().findAll( entityType, ids );
|
return this.lazySession.get().findAll( entityType, ids, options );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -6,13 +6,18 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.internal;
|
package org.hibernate.internal;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
|
|
||||||
import org.hibernate.CacheMode;
|
import org.hibernate.CacheMode;
|
||||||
import org.hibernate.LockOptions;
|
import org.hibernate.LockOptions;
|
||||||
import org.hibernate.MultiIdentifierLoadAccess;
|
import org.hibernate.MultiIdentifierLoadAccess;
|
||||||
|
import org.hibernate.UnknownProfileException;
|
||||||
|
import org.hibernate.engine.spi.EffectiveEntityGraph;
|
||||||
|
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
import org.hibernate.graph.GraphSemantic;
|
import org.hibernate.graph.GraphSemantic;
|
||||||
import org.hibernate.graph.RootGraph;
|
import org.hibernate.graph.RootGraph;
|
||||||
import org.hibernate.graph.spi.RootGraphImplementor;
|
import org.hibernate.graph.spi.RootGraphImplementor;
|
||||||
|
@ -20,6 +25,8 @@ import org.hibernate.loader.ast.internal.LoaderHelper;
|
||||||
import org.hibernate.persister.entity.EntityPersister;
|
import org.hibernate.persister.entity.EntityPersister;
|
||||||
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
|
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
|
||||||
|
|
||||||
|
import static java.util.Collections.emptyList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
|
@ -29,6 +36,7 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
|
||||||
|
|
||||||
private LockOptions lockOptions;
|
private LockOptions lockOptions;
|
||||||
private CacheMode cacheMode;
|
private CacheMode cacheMode;
|
||||||
|
private Boolean readOnly;
|
||||||
|
|
||||||
private RootGraphImplementor<T> rootGraph;
|
private RootGraphImplementor<T> rootGraph;
|
||||||
private GraphSemantic graphSemantic;
|
private GraphSemantic graphSemantic;
|
||||||
|
@ -38,6 +46,9 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
|
||||||
private boolean returnOfDeletedEntitiesEnabled;
|
private boolean returnOfDeletedEntitiesEnabled;
|
||||||
private boolean orderedReturnEnabled = true;
|
private boolean orderedReturnEnabled = true;
|
||||||
|
|
||||||
|
private Set<String> enabledFetchProfiles;
|
||||||
|
private Set<String> disabledFetchProfiles;
|
||||||
|
|
||||||
public MultiIdentifierLoadAccessImpl(SessionImpl session, EntityPersister entityPersister) {
|
public MultiIdentifierLoadAccessImpl(SessionImpl session, EntityPersister entityPersister) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.entityPersister = entityPersister;
|
this.entityPersister = entityPersister;
|
||||||
|
@ -60,6 +71,12 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiIdentifierLoadAccess<T> withReadOnly(boolean readOnly) {
|
||||||
|
this.readOnly = readOnly;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MultiIdentifierLoadAccess<T> with(RootGraph<T> graph, GraphSemantic semantic) {
|
public MultiIdentifierLoadAccess<T> with(RootGraph<T> graph, GraphSemantic semantic) {
|
||||||
this.rootGraph = (RootGraphImplementor<T>) graph;
|
this.rootGraph = (RootGraphImplementor<T>) graph;
|
||||||
|
@ -121,6 +138,13 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Boolean getReadOnly(SessionImplementor session) {
|
||||||
|
return readOnly != null
|
||||||
|
? readOnly
|
||||||
|
: session.getLoadQueryInfluencers().getReadOnly();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public <K> List<T> multiLoad(K... ids) {
|
public <K> List<T> multiLoad(K... ids) {
|
||||||
|
@ -128,7 +152,7 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<T> perform(Supplier<List<T>> executor) {
|
public List<T> perform(Supplier<List<T>> executor) {
|
||||||
CacheMode sessionCacheMode = session.getCacheMode();
|
final CacheMode sessionCacheMode = session.getCacheMode();
|
||||||
boolean cacheModeChanged = false;
|
boolean cacheModeChanged = false;
|
||||||
if ( cacheMode != null ) {
|
if ( cacheMode != null ) {
|
||||||
// naive check for now...
|
// naive check for now...
|
||||||
|
@ -140,20 +164,17 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if ( graphSemantic != null ) {
|
final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers();
|
||||||
if ( rootGraph == null ) {
|
final HashSet<String> fetchProfiles =
|
||||||
throw new IllegalArgumentException( "Graph semantic specified, but no RootGraph was supplied" );
|
influencers.adjustFetchProfiles( disabledFetchProfiles, enabledFetchProfiles );
|
||||||
}
|
final EffectiveEntityGraph effectiveEntityGraph =
|
||||||
session.getLoadQueryInfluencers().getEffectiveEntityGraph().applyGraph( rootGraph, graphSemantic );
|
influencers.applyEntityGraph( rootGraph, graphSemantic );
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return executor.get();
|
return executor.get();
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if ( graphSemantic != null ) {
|
effectiveEntityGraph.clear();
|
||||||
session.getLoadQueryInfluencers().getEffectiveEntityGraph().clear();
|
influencers.setEnabledFetchProfileNames( fetchProfiles );
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
|
@ -168,12 +189,41 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
|
||||||
@SuppressWarnings( "unchecked" )
|
@SuppressWarnings( "unchecked" )
|
||||||
public <K> List<T> multiLoad(List<K> ids) {
|
public <K> List<T> multiLoad(List<K> ids) {
|
||||||
if ( ids.isEmpty() ) {
|
if ( ids.isEmpty() ) {
|
||||||
return Collections.emptyList();
|
return emptyList();
|
||||||
}
|
}
|
||||||
return perform( () -> (List<T>) entityPersister.multiLoad(
|
else {
|
||||||
ids.toArray( LoaderHelper.createTypedArray( ids.get( 0 ).getClass(), ids.size() ) ),
|
return perform( () -> (List<T>) entityPersister.multiLoad(
|
||||||
session,
|
ids.toArray( LoaderHelper.createTypedArray( ids.get( 0 ).getClass(), ids.size() ) ),
|
||||||
this
|
session,
|
||||||
) );
|
this
|
||||||
|
) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiIdentifierLoadAccess<T> enableFetchProfile(String profileName) {
|
||||||
|
if ( !session.getFactory().containsFetchProfileDefinition( profileName ) ) {
|
||||||
|
throw new UnknownProfileException( profileName );
|
||||||
|
}
|
||||||
|
if ( enabledFetchProfiles == null ) {
|
||||||
|
enabledFetchProfiles = new HashSet<>();
|
||||||
|
}
|
||||||
|
enabledFetchProfiles.add( profileName );
|
||||||
|
if ( disabledFetchProfiles != null ) {
|
||||||
|
disabledFetchProfiles.remove( profileName );
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public MultiIdentifierLoadAccess<T> disableFetchProfile(String profileName) {
|
||||||
|
if ( disabledFetchProfiles == null ) {
|
||||||
|
disabledFetchProfiles = new HashSet<>();
|
||||||
|
}
|
||||||
|
disabledFetchProfiles.add( profileName );
|
||||||
|
if ( enabledFetchProfiles != null ) {
|
||||||
|
enabledFetchProfiles.remove( profileName );
|
||||||
|
}
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -944,22 +944,64 @@ public class SessionImpl
|
||||||
|
|
||||||
@Override @Deprecated
|
@Override @Deprecated
|
||||||
public Object load(String entityName, Object id) throws HibernateException {
|
public Object load(String entityName, Object id) throws HibernateException {
|
||||||
return this.byId( entityName ).getReference( id );
|
return byId( entityName ).getReference( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
private <T> MultiIdentifierLoadAccess<T> multiloadAccessWithOptions(Class<T> entityClass, FindOption[] options) {
|
||||||
|
final MultiIdentifierLoadAccess<T> loadAccess = byMultipleIds( entityClass );
|
||||||
|
CacheStoreMode storeMode = getCacheStoreMode();
|
||||||
|
CacheRetrieveMode retrieveMode = getCacheRetrieveMode();
|
||||||
|
LockOptions lockOptions = copySessionLockOptions();
|
||||||
|
for ( FindOption option : options ) {
|
||||||
|
if ( option instanceof CacheStoreMode cacheStoreMode ) {
|
||||||
|
storeMode = cacheStoreMode;
|
||||||
|
}
|
||||||
|
else if ( option instanceof CacheRetrieveMode cacheRetrieveMode ) {
|
||||||
|
retrieveMode = cacheRetrieveMode;
|
||||||
|
}
|
||||||
|
else if ( option instanceof CacheMode cacheMode ) {
|
||||||
|
storeMode = cacheMode.getJpaStoreMode();
|
||||||
|
retrieveMode = cacheMode.getJpaRetrieveMode();
|
||||||
|
}
|
||||||
|
else if ( option instanceof LockModeType lockModeType ) {
|
||||||
|
lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
|
||||||
|
}
|
||||||
|
else if ( option instanceof LockMode lockMode ) {
|
||||||
|
lockOptions.setLockMode( lockMode );
|
||||||
|
}
|
||||||
|
else if ( option instanceof LockOptions lockOpts ) {
|
||||||
|
lockOptions = lockOpts;
|
||||||
|
}
|
||||||
|
else if ( option instanceof PessimisticLockScope pessimisticLockScope ) {
|
||||||
|
lockOptions.setLockScope( pessimisticLockScope );
|
||||||
|
}
|
||||||
|
else if ( option instanceof Timeout timeout ) {
|
||||||
|
lockOptions.setTimeOut( timeout.milliseconds() );
|
||||||
|
}
|
||||||
|
else if ( option instanceof EnabledFetchProfile enabledFetchProfile ) {
|
||||||
|
loadAccess.enableFetchProfile( enabledFetchProfile.profileName() );
|
||||||
|
}
|
||||||
|
else if ( option instanceof ReadOnlyMode ) {
|
||||||
|
loadAccess.withReadOnly( option == ReadOnlyMode.READ_ONLY );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
loadAccess.with( lockOptions ).with( interpretCacheMode( storeMode, retrieveMode ) );
|
||||||
|
return loadAccess;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <E> List<E> findAll(Class<E> entityType, List<Object> ids) {
|
public <E> List<E> findAll(Class<E> entityType, List<Object> ids, FindOption... options) {
|
||||||
return this.byMultipleIds( entityType ).multiLoad( ids );
|
return multiloadAccessWithOptions( entityType, options ).multiLoad( ids );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T get(Class<T> entityClass, Object id) throws HibernateException {
|
public <T> T get(Class<T> entityClass, Object id) throws HibernateException {
|
||||||
return this.byId( entityClass ).load( id );
|
return byId( entityClass ).load( id );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object get(String entityName, Object id) throws HibernateException {
|
public Object get(String entityName, Object id) throws HibernateException {
|
||||||
return this.byId( entityName ).load( id );
|
return byId( entityName ).load( id );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -2360,6 +2402,10 @@ public class SessionImpl
|
||||||
else if ( option instanceof CacheRetrieveMode cacheRetrieveMode ) {
|
else if ( option instanceof CacheRetrieveMode cacheRetrieveMode ) {
|
||||||
retrieveMode = cacheRetrieveMode;
|
retrieveMode = cacheRetrieveMode;
|
||||||
}
|
}
|
||||||
|
else if ( option instanceof CacheMode cacheMode ) {
|
||||||
|
storeMode = cacheMode.getJpaStoreMode();
|
||||||
|
retrieveMode = cacheMode.getJpaRetrieveMode();
|
||||||
|
}
|
||||||
else if ( option instanceof LockModeType lockModeType ) {
|
else if ( option instanceof LockModeType lockModeType ) {
|
||||||
lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
|
lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,17 +9,27 @@ package org.hibernate.loader.ast.internal;
|
||||||
import org.hibernate.engine.spi.EntityHolder;
|
import org.hibernate.engine.spi.EntityHolder;
|
||||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
import org.hibernate.engine.spi.SubselectFetch;
|
import org.hibernate.engine.spi.SubselectFetch;
|
||||||
|
import org.hibernate.query.spi.QueryOptions;
|
||||||
import org.hibernate.sql.exec.internal.BaseExecutionContext;
|
import org.hibernate.sql.exec.internal.BaseExecutionContext;
|
||||||
|
|
||||||
class ExecutionContextWithSubselectFetchHandler extends BaseExecutionContext {
|
class ExecutionContextWithSubselectFetchHandler extends BaseExecutionContext {
|
||||||
|
|
||||||
private final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
|
private final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
|
||||||
|
private final boolean readOnly;
|
||||||
|
|
||||||
public ExecutionContextWithSubselectFetchHandler(
|
public ExecutionContextWithSubselectFetchHandler(
|
||||||
SharedSessionContractImplementor session,
|
SharedSessionContractImplementor session,
|
||||||
SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler) {
|
SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler) {
|
||||||
|
this( session, subSelectFetchableKeysHandler, false );
|
||||||
|
}
|
||||||
|
|
||||||
|
public ExecutionContextWithSubselectFetchHandler(
|
||||||
|
SharedSessionContractImplementor session,
|
||||||
|
SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler,
|
||||||
|
boolean readOnly) {
|
||||||
super( session );
|
super( session );
|
||||||
this.subSelectFetchableKeysHandler = subSelectFetchableKeysHandler;
|
this.subSelectFetchableKeysHandler = subSelectFetchableKeysHandler;
|
||||||
|
this.readOnly = readOnly;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -29,4 +39,8 @@ class ExecutionContextWithSubselectFetchHandler extends BaseExecutionContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public QueryOptions getQueryOptions() {
|
||||||
|
return readOnly ? QueryOptions.READ_ONLY : super.getQueryOptions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,6 +43,7 @@ import org.hibernate.sql.results.spi.ManagedResultConsumer;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
|
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -193,7 +194,9 @@ public class MultiIdEntityLoaderArrayParam<E> extends AbstractMultiIdEntityLoade
|
||||||
session.getJdbcServices().getJdbcSelectExecutor().executeQuery(
|
session.getJdbcServices().getJdbcSelectExecutor().executeQuery(
|
||||||
jdbcSelectOperation,
|
jdbcSelectOperation,
|
||||||
jdbcParameterBindings,
|
jdbcParameterBindings,
|
||||||
new ExecutionContextWithSubselectFetchHandler( session, subSelectFetchableKeysHandler ),
|
new ExecutionContextWithSubselectFetchHandler( session,
|
||||||
|
subSelectFetchableKeysHandler,
|
||||||
|
TRUE.equals( loadOptions.getReadOnly(session) ) ),
|
||||||
RowTransformerStandardImpl.instance(),
|
RowTransformerStandardImpl.instance(),
|
||||||
null,
|
null,
|
||||||
idsToLoadFromDatabase.size(),
|
idsToLoadFromDatabase.size(),
|
||||||
|
|
|
@ -40,6 +40,8 @@ import org.hibernate.sql.results.spi.ListResultsConsumer;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
|
||||||
|
import static java.lang.Boolean.TRUE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Standard MultiIdEntityLoader
|
* Standard MultiIdEntityLoader
|
||||||
*
|
*
|
||||||
|
@ -157,7 +159,7 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
||||||
|
|
||||||
if ( idsInBatch.size() >= maxBatchSize ) {
|
if ( idsInBatch.size() >= maxBatchSize ) {
|
||||||
// we've hit the allotted max-batch-size, perform an "intermediate load"
|
// we've hit the allotted max-batch-size, perform an "intermediate load"
|
||||||
loadEntitiesById( idsInBatch, lockOptions, session );
|
loadEntitiesById( idsInBatch, lockOptions, loadOptions, session );
|
||||||
idsInBatch.clear();
|
idsInBatch.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -169,7 +171,7 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
||||||
if ( !idsInBatch.isEmpty() ) {
|
if ( !idsInBatch.isEmpty() ) {
|
||||||
// we still have ids to load from the processing above since the last max-batch-size trigger,
|
// we still have ids to load from the processing above since the last max-batch-size trigger,
|
||||||
// perform a load for them
|
// perform a load for them
|
||||||
loadEntitiesById( idsInBatch, lockOptions, session );
|
loadEntitiesById( idsInBatch, lockOptions, loadOptions, session );
|
||||||
}
|
}
|
||||||
|
|
||||||
// for each result where we set the EntityKey earlier, replace them
|
// for each result where we set the EntityKey earlier, replace them
|
||||||
|
@ -197,7 +199,8 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
||||||
private List<T> loadEntitiesById(
|
private List<T> loadEntitiesById(
|
||||||
List<Object> idsInBatch,
|
List<Object> idsInBatch,
|
||||||
LockOptions lockOptions,
|
LockOptions lockOptions,
|
||||||
SharedSessionContractImplementor session) {
|
MultiIdLoadOptions loadOptions,
|
||||||
|
EventSource session) {
|
||||||
assert idsInBatch != null;
|
assert idsInBatch != null;
|
||||||
assert ! idsInBatch.isEmpty();
|
assert ! idsInBatch.isEmpty();
|
||||||
|
|
||||||
|
@ -265,7 +268,9 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
||||||
return session.getJdbcServices().getJdbcSelectExecutor().list(
|
return session.getJdbcServices().getJdbcSelectExecutor().list(
|
||||||
jdbcSelect,
|
jdbcSelect,
|
||||||
jdbcParameterBindings,
|
jdbcParameterBindings,
|
||||||
new ExecutionContextWithSubselectFetchHandler( session, subSelectFetchableKeysHandler ),
|
new ExecutionContextWithSubselectFetchHandler( session,
|
||||||
|
subSelectFetchableKeysHandler,
|
||||||
|
TRUE.equals( loadOptions.getReadOnly(session) ) ),
|
||||||
RowTransformerStandardImpl.instance(),
|
RowTransformerStandardImpl.instance(),
|
||||||
null,
|
null,
|
||||||
ListResultsConsumer.UniqueSemantic.FILTER,
|
ListResultsConsumer.UniqueSemantic.FILTER,
|
||||||
|
@ -403,7 +408,7 @@ public class MultiIdEntityLoaderStandard<T> extends AbstractMultiIdEntityLoader<
|
||||||
System.arraycopy( ids, idPosition, idsInBatch, 0, batchSize );
|
System.arraycopy( ids, idPosition, idsInBatch, 0, batchSize );
|
||||||
|
|
||||||
result.addAll(
|
result.addAll(
|
||||||
loadEntitiesById( Arrays.asList( idsInBatch ), lockOptions, session )
|
loadEntitiesById( Arrays.asList( idsInBatch ), lockOptions, loadOptions, session )
|
||||||
);
|
);
|
||||||
|
|
||||||
numberOfIdsLeft = numberOfIdsLeft - batchSize;
|
numberOfIdsLeft = numberOfIdsLeft - batchSize;
|
||||||
|
|
|
@ -6,6 +6,8 @@
|
||||||
*/
|
*/
|
||||||
package org.hibernate.loader.ast.spi;
|
package org.hibernate.loader.ast.spi;
|
||||||
|
|
||||||
|
import org.hibernate.engine.spi.SessionImplementor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encapsulation of the options for loading multiple entities by id
|
* Encapsulation of the options for loading multiple entities by id
|
||||||
*/
|
*/
|
||||||
|
@ -25,4 +27,9 @@ public interface MultiIdLoadOptions extends MultiLoadOptions {
|
||||||
* @return the session factory cache is checked first
|
* @return the session factory cache is checked first
|
||||||
*/
|
*/
|
||||||
boolean isSecondLevelCacheCheckingEnabled();
|
boolean isSecondLevelCacheCheckingEnabled();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Should the entities be loaded in read-only mode?
|
||||||
|
*/
|
||||||
|
Boolean getReadOnly(SessionImplementor session);
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,7 +108,7 @@ public class IdentifierLoadAccessImpl<T> implements IdentifierLoadAccess<T>, Jav
|
||||||
final HashSet<String> fetchProfiles =
|
final HashSet<String> fetchProfiles =
|
||||||
influencers.adjustFetchProfiles( disabledFetchProfiles, enabledFetchProfiles );
|
influencers.adjustFetchProfiles( disabledFetchProfiles, enabledFetchProfiles );
|
||||||
final EffectiveEntityGraph effectiveEntityGraph =
|
final EffectiveEntityGraph effectiveEntityGraph =
|
||||||
session.getLoadQueryInfluencers().applyEntityGraph( rootGraph, graphSemantic);
|
influencers.applyEntityGraph( rootGraph, graphSemantic);
|
||||||
try {
|
try {
|
||||||
return executor.get();
|
return executor.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,80 @@
|
||||||
|
package org.hibernate.orm.test.loading.multiLoad;
|
||||||
|
|
||||||
|
import jakarta.persistence.Entity;
|
||||||
|
import jakarta.persistence.FetchType;
|
||||||
|
import jakarta.persistence.Id;
|
||||||
|
import jakarta.persistence.ManyToOne;
|
||||||
|
import org.hibernate.EnabledFetchProfile;
|
||||||
|
import org.hibernate.Hibernate;
|
||||||
|
import org.hibernate.annotations.FetchProfile;
|
||||||
|
import org.hibernate.annotations.FetchProfileOverride;
|
||||||
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
@SessionFactory
|
||||||
|
@DomainModel(annotatedClasses = {FindAllFetchProfileTest.Record.class, FindAllFetchProfileTest.Owner.class})
|
||||||
|
public class FindAllFetchProfileTest {
|
||||||
|
@Test void test(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction(s-> {
|
||||||
|
Owner gavin = new Owner("gavin");
|
||||||
|
s.persist(gavin);
|
||||||
|
s.persist(new Record(123L,gavin,"hello earth"));
|
||||||
|
s.persist(new Record(456L,gavin,"hello mars"));
|
||||||
|
});
|
||||||
|
scope.inTransaction(s-> {
|
||||||
|
List<Record> all = s.findAll(Record.class, List.of(456L, 123L, 2L));
|
||||||
|
assertEquals("hello mars",all.get(0).message);
|
||||||
|
assertEquals("hello earth",all.get(1).message);
|
||||||
|
assertNull(all.get(2));
|
||||||
|
assertFalse(Hibernate.isInitialized(all.get(0).owner));
|
||||||
|
assertFalse(Hibernate.isInitialized(all.get(1).owner));
|
||||||
|
});
|
||||||
|
scope.inTransaction(s-> {
|
||||||
|
List<Record> all = s.findAll(Record.class, List.of(456L, 123L),
|
||||||
|
new EnabledFetchProfile("withOwner"));
|
||||||
|
assertEquals("hello mars",all.get(0).message);
|
||||||
|
assertEquals("hello earth",all.get(1).message);
|
||||||
|
assertTrue(Hibernate.isInitialized(all.get(0).owner));
|
||||||
|
assertTrue(Hibernate.isInitialized(all.get(1).owner));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@Entity
|
||||||
|
@FetchProfile(name = "withOwner")
|
||||||
|
static class Record {
|
||||||
|
@Id Long id;
|
||||||
|
String message;
|
||||||
|
|
||||||
|
@FetchProfileOverride(profile = "withOwner")
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
Owner owner;
|
||||||
|
|
||||||
|
Record(Long id, Owner owner, String message) {
|
||||||
|
this.id = id;
|
||||||
|
this.owner = owner;
|
||||||
|
this.message = message;
|
||||||
|
}
|
||||||
|
|
||||||
|
Record() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@Entity
|
||||||
|
static class Owner {
|
||||||
|
@Id String name;
|
||||||
|
|
||||||
|
Owner(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
Owner() {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,8 +9,10 @@ import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.hibernate.ReadOnlyMode.READ_ONLY;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@DomainModel(annotatedClasses = FindAllTest.Record.class)
|
@DomainModel(annotatedClasses = FindAllTest.Record.class)
|
||||||
|
@ -26,6 +28,13 @@ public class FindAllTest {
|
||||||
assertEquals("hello earth",all.get(1).message);
|
assertEquals("hello earth",all.get(1).message);
|
||||||
assertNull(all.get(2));
|
assertNull(all.get(2));
|
||||||
});
|
});
|
||||||
|
scope.inTransaction(s-> {
|
||||||
|
List<Record> all = s.findAll(Record.class, List.of(456L, 123L), READ_ONLY);
|
||||||
|
assertEquals("hello mars",all.get(0).message);
|
||||||
|
assertEquals("hello earth",all.get(1).message);
|
||||||
|
assertTrue(s.isReadOnly(all.get(0)));
|
||||||
|
assertTrue(s.isReadOnly(all.get(1)));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@Entity
|
@Entity
|
||||||
static class Record {
|
static class Record {
|
||||||
|
|
|
@ -9,8 +9,8 @@ import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.Assert.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
|
||||||
@SessionFactory
|
@SessionFactory
|
||||||
@DomainModel(annotatedClasses = GetAllTest.Record.class)
|
@DomainModel(annotatedClasses = GetAllTest.Record.class)
|
||||||
|
|
Loading…
Reference in New Issue