Skip to content

Commit 6e2ed7f

Browse files
committed
HHH-17948 make findAll() accept FindOptions
and add missing options to MultiIdentifierLoadAccess
1 parent 62e1b04 commit 6e2ed7f

15 files changed

+291
-42
lines changed

hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,15 @@ public interface MultiIdentifierLoadAccess<T> {
5151
*/
5252
MultiIdentifierLoadAccess<T> with(CacheMode cacheMode);
5353

54+
/**
55+
* Specify whether the entities should be loaded in read-only mode.
56+
*
57+
* @see Session#setDefaultReadOnly(boolean)
58+
*
59+
* @since 7.0
60+
*/
61+
MultiIdentifierLoadAccess<T> withReadOnly(boolean readOnly);
62+
5463
/**
5564
* Override the associations fetched by default by specifying
5665
* the complete list of associations to be fetched as an
@@ -88,6 +97,30 @@ default MultiIdentifierLoadAccess<T> with(RootGraph<T> graph) {
8897
*/
8998
MultiIdentifierLoadAccess<T> with(RootGraph<T> graph, GraphSemantic semantic);
9099

100+
/**
101+
* Customize the associations fetched by specifying a
102+
* {@linkplain org.hibernate.annotations.FetchProfile fetch profile}
103+
* that should be enabled during this operation.
104+
* <p>
105+
* This allows the {@linkplain Session#isFetchProfileEnabled(String)
106+
* session-level fetch profiles} to be temporarily overridden.
107+
*
108+
* @since 7.0
109+
*/
110+
MultiIdentifierLoadAccess<T> enableFetchProfile(String profileName);
111+
112+
/**
113+
* Customize the associations fetched by specifying a
114+
* {@linkplain org.hibernate.annotations.FetchProfile fetch profile}
115+
* that should be disabled during this operation.
116+
* <p>
117+
* This allows the {@linkplain Session#isFetchProfileEnabled(String)
118+
* session-level fetch profiles} to be temporarily overridden.
119+
*
120+
* @since 7.0
121+
*/
122+
MultiIdentifierLoadAccess<T> disableFetchProfile(String profileName);
123+
91124
/**
92125
* Specify a batch size, that is, how many entities should be
93126
* fetched in each request to the database.

hibernate-core/src/main/java/org/hibernate/Session.java

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.List;
1010
import java.util.function.Consumer;
1111

12+
import jakarta.persistence.FindOption;
1213
import org.hibernate.graph.RootGraph;
1314
import org.hibernate.jdbc.Work;
1415
import org.hibernate.query.Query;
@@ -706,12 +707,13 @@ public interface Session extends SharedSessionContract, EntityManager {
706707
*
707708
* @param entityType the entity type
708709
* @param ids the identifiers
710+
* @param options options, if any
709711
* @return an ordered list of persistent instances, with null elements representing missing
710-
* entities
712+
* entities
711713
* @see #byMultipleIds(Class)
712714
* @since 7.0
713715
*/
714-
<E> List<E> findAll(Class<E> entityType, List<Object> ids);
716+
<E> List<E> findAll(Class<E> entityType, List<Object> ids, FindOption... options);
715717

716718
/**
717719
* Return the persistent instance of the given entity class with the given identifier,
@@ -922,7 +924,7 @@ public interface Session extends SharedSessionContract, EntityManager {
922924
*
923925
* @throws HibernateException If the given class does not resolve as a mapped entity
924926
*
925-
* @see #findAll(Class, List)
927+
* @see #findAll(Class, List, FindOption...)
926928
*/
927929
<T> MultiIdentifierLoadAccess<T> byMultipleIds(Class<T> entityClass);
928930

hibernate-core/src/main/java/org/hibernate/StatelessSession.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -262,7 +262,7 @@ public interface StatelessSession extends SharedSessionContract {
262262
* @param entityClass The class of the entity to retrieve
263263
* @param ids The ids of the entities to retrieve
264264
* @return an ordered list of detached entity instances, with
265-
* null elements representing missing entities
265+
* null elements representing missing entities
266266
* @since 7.0
267267
*/
268268
<T> List<T> getAll(Class<T> entityClass, List<Object> ids);

hibernate-core/src/main/java/org/hibernate/engine/spi/SessionDelegatorBaseImpl.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -954,8 +954,8 @@ public void detach(Object entity) {
954954
}
955955

956956
@Override
957-
public <E> List<E> findAll(Class<E> entityType, List<Object> ids) {
958-
return delegate.findAll( entityType, ids );
957+
public <E> List<E> findAll(Class<E> entityType, List<Object> ids, FindOption... options) {
958+
return delegate.findAll( entityType, ids, options );
959959
}
960960

961961
@Override

hibernate-core/src/main/java/org/hibernate/engine/spi/SessionLazyDelegator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,8 +264,8 @@ public void clear() {
264264
}
265265

266266
@Override
267-
public <E> List<E> findAll(Class<E> entityType, List<Object> ids) {
268-
return this.lazySession.get().findAll( entityType, ids );
267+
public <E> List<E> findAll(Class<E> entityType, List<Object> ids, FindOption... options) {
268+
return this.lazySession.get().findAll( entityType, ids, options );
269269
}
270270

271271
@Override

hibernate-core/src/main/java/org/hibernate/internal/MultiIdentifierLoadAccessImpl.java

Lines changed: 68 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,27 @@
66
*/
77
package org.hibernate.internal;
88

9-
import java.util.Collections;
9+
import java.util.HashSet;
1010
import java.util.List;
11+
import java.util.Set;
1112
import java.util.function.Supplier;
1213

1314
import org.hibernate.CacheMode;
1415
import org.hibernate.LockOptions;
1516
import org.hibernate.MultiIdentifierLoadAccess;
17+
import org.hibernate.UnknownProfileException;
18+
import org.hibernate.engine.spi.EffectiveEntityGraph;
19+
import org.hibernate.engine.spi.LoadQueryInfluencers;
20+
import org.hibernate.engine.spi.SessionImplementor;
1621
import org.hibernate.graph.GraphSemantic;
1722
import org.hibernate.graph.RootGraph;
1823
import org.hibernate.graph.spi.RootGraphImplementor;
1924
import org.hibernate.loader.ast.internal.LoaderHelper;
2025
import org.hibernate.persister.entity.EntityPersister;
2126
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
2227

28+
import static java.util.Collections.emptyList;
29+
2330
/**
2431
* @author Steve Ebersole
2532
*/
@@ -29,6 +36,7 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
2936

3037
private LockOptions lockOptions;
3138
private CacheMode cacheMode;
39+
private Boolean readOnly;
3240

3341
private RootGraphImplementor<T> rootGraph;
3442
private GraphSemantic graphSemantic;
@@ -38,6 +46,9 @@ class MultiIdentifierLoadAccessImpl<T> implements MultiIdentifierLoadAccess<T>,
3846
private boolean returnOfDeletedEntitiesEnabled;
3947
private boolean orderedReturnEnabled = true;
4048

49+
private Set<String> enabledFetchProfiles;
50+
private Set<String> disabledFetchProfiles;
51+
4152
public MultiIdentifierLoadAccessImpl(SessionImpl session, EntityPersister entityPersister) {
4253
this.session = session;
4354
this.entityPersister = entityPersister;
@@ -60,6 +71,12 @@ public MultiIdentifierLoadAccess<T> with(CacheMode cacheMode) {
6071
return this;
6172
}
6273

74+
@Override
75+
public MultiIdentifierLoadAccess<T> withReadOnly(boolean readOnly) {
76+
this.readOnly = readOnly;
77+
return this;
78+
}
79+
6380
@Override
6481
public MultiIdentifierLoadAccess<T> with(RootGraph<T> graph, GraphSemantic semantic) {
6582
this.rootGraph = (RootGraphImplementor<T>) graph;
@@ -121,14 +138,21 @@ public MultiIdentifierLoadAccess<T> enableOrderedReturn(boolean enabled) {
121138
return this;
122139
}
123140

141+
@Override
142+
public Boolean getReadOnly(SessionImplementor session) {
143+
return readOnly != null
144+
? readOnly
145+
: session.getLoadQueryInfluencers().getReadOnly();
146+
}
147+
124148
@Override
125149
@SuppressWarnings( "unchecked" )
126150
public <K> List<T> multiLoad(K... ids) {
127151
return perform( () -> (List<T>) entityPersister.multiLoad( ids, session, this ) );
128152
}
129153

130154
public List<T> perform(Supplier<List<T>> executor) {
131-
CacheMode sessionCacheMode = session.getCacheMode();
155+
final CacheMode sessionCacheMode = session.getCacheMode();
132156
boolean cacheModeChanged = false;
133157
if ( cacheMode != null ) {
134158
// naive check for now...
@@ -140,20 +164,17 @@ public List<T> perform(Supplier<List<T>> executor) {
140164
}
141165

142166
try {
143-
if ( graphSemantic != null ) {
144-
if ( rootGraph == null ) {
145-
throw new IllegalArgumentException( "Graph semantic specified, but no RootGraph was supplied" );
146-
}
147-
session.getLoadQueryInfluencers().getEffectiveEntityGraph().applyGraph( rootGraph, graphSemantic );
148-
}
149-
167+
final LoadQueryInfluencers influencers = session.getLoadQueryInfluencers();
168+
final HashSet<String> fetchProfiles =
169+
influencers.adjustFetchProfiles( disabledFetchProfiles, enabledFetchProfiles );
170+
final EffectiveEntityGraph effectiveEntityGraph =
171+
influencers.applyEntityGraph( rootGraph, graphSemantic );
150172
try {
151173
return executor.get();
152174
}
153175
finally {
154-
if ( graphSemantic != null ) {
155-
session.getLoadQueryInfluencers().getEffectiveEntityGraph().clear();
156-
}
176+
effectiveEntityGraph.clear();
177+
influencers.setEnabledFetchProfileNames( fetchProfiles );
157178
}
158179
}
159180
finally {
@@ -168,12 +189,41 @@ public List<T> perform(Supplier<List<T>> executor) {
168189
@SuppressWarnings( "unchecked" )
169190
public <K> List<T> multiLoad(List<K> ids) {
170191
if ( ids.isEmpty() ) {
171-
return Collections.emptyList();
192+
return emptyList();
193+
}
194+
else {
195+
return perform( () -> (List<T>) entityPersister.multiLoad(
196+
ids.toArray( LoaderHelper.createTypedArray( ids.get( 0 ).getClass(), ids.size() ) ),
197+
session,
198+
this
199+
) );
172200
}
173-
return perform( () -> (List<T>) entityPersister.multiLoad(
174-
ids.toArray( LoaderHelper.createTypedArray( ids.get( 0 ).getClass(), ids.size() ) ),
175-
session,
176-
this
177-
) );
201+
}
202+
203+
@Override
204+
public MultiIdentifierLoadAccess<T> enableFetchProfile(String profileName) {
205+
if ( !session.getFactory().containsFetchProfileDefinition( profileName ) ) {
206+
throw new UnknownProfileException( profileName );
207+
}
208+
if ( enabledFetchProfiles == null ) {
209+
enabledFetchProfiles = new HashSet<>();
210+
}
211+
enabledFetchProfiles.add( profileName );
212+
if ( disabledFetchProfiles != null ) {
213+
disabledFetchProfiles.remove( profileName );
214+
}
215+
return this;
216+
}
217+
218+
@Override
219+
public MultiIdentifierLoadAccess<T> disableFetchProfile(String profileName) {
220+
if ( disabledFetchProfiles == null ) {
221+
disabledFetchProfiles = new HashSet<>();
222+
}
223+
disabledFetchProfiles.add( profileName );
224+
if ( enabledFetchProfiles != null ) {
225+
enabledFetchProfiles.remove( profileName );
226+
}
227+
return this;
178228
}
179229
}

hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -944,22 +944,64 @@ public void load(Object object, Object id) throws HibernateException {
944944

945945
@Override @Deprecated
946946
public Object load(String entityName, Object id) throws HibernateException {
947-
return this.byId( entityName ).getReference( id );
947+
return byId( entityName ).getReference( id );
948+
}
949+
950+
private <T> MultiIdentifierLoadAccess<T> multiloadAccessWithOptions(Class<T> entityClass, FindOption[] options) {
951+
final MultiIdentifierLoadAccess<T> loadAccess = byMultipleIds( entityClass );
952+
CacheStoreMode storeMode = getCacheStoreMode();
953+
CacheRetrieveMode retrieveMode = getCacheRetrieveMode();
954+
LockOptions lockOptions = copySessionLockOptions();
955+
for ( FindOption option : options ) {
956+
if ( option instanceof CacheStoreMode cacheStoreMode ) {
957+
storeMode = cacheStoreMode;
958+
}
959+
else if ( option instanceof CacheRetrieveMode cacheRetrieveMode ) {
960+
retrieveMode = cacheRetrieveMode;
961+
}
962+
else if ( option instanceof CacheMode cacheMode ) {
963+
storeMode = cacheMode.getJpaStoreMode();
964+
retrieveMode = cacheMode.getJpaRetrieveMode();
965+
}
966+
else if ( option instanceof LockModeType lockModeType ) {
967+
lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
968+
}
969+
else if ( option instanceof LockMode lockMode ) {
970+
lockOptions.setLockMode( lockMode );
971+
}
972+
else if ( option instanceof LockOptions lockOpts ) {
973+
lockOptions = lockOpts;
974+
}
975+
else if ( option instanceof PessimisticLockScope pessimisticLockScope ) {
976+
lockOptions.setLockScope( pessimisticLockScope );
977+
}
978+
else if ( option instanceof Timeout timeout ) {
979+
lockOptions.setTimeOut( timeout.milliseconds() );
980+
}
981+
else if ( option instanceof EnabledFetchProfile enabledFetchProfile ) {
982+
loadAccess.enableFetchProfile( enabledFetchProfile.profileName() );
983+
}
984+
else if ( option instanceof ReadOnlyMode ) {
985+
loadAccess.withReadOnly( option == ReadOnlyMode.READ_ONLY );
986+
}
987+
}
988+
loadAccess.with( lockOptions ).with( interpretCacheMode( storeMode, retrieveMode ) );
989+
return loadAccess;
948990
}
949991

950992
@Override
951-
public <E> List<E> findAll(Class<E> entityType, List<Object> ids) {
952-
return this.byMultipleIds( entityType ).multiLoad( ids );
993+
public <E> List<E> findAll(Class<E> entityType, List<Object> ids, FindOption... options) {
994+
return multiloadAccessWithOptions( entityType, options ).multiLoad( ids );
953995
}
954996

955997
@Override
956998
public <T> T get(Class<T> entityClass, Object id) throws HibernateException {
957-
return this.byId( entityClass ).load( id );
999+
return byId( entityClass ).load( id );
9581000
}
9591001

9601002
@Override
9611003
public Object get(String entityName, Object id) throws HibernateException {
962-
return this.byId( entityName ).load( id );
1004+
return byId( entityName ).load( id );
9631005
}
9641006

9651007
/**
@@ -2360,6 +2402,10 @@ private <T> IdentifierLoadAccessImpl<T> loadAccessWithOptions(Class<T> entityCla
23602402
else if ( option instanceof CacheRetrieveMode cacheRetrieveMode ) {
23612403
retrieveMode = cacheRetrieveMode;
23622404
}
2405+
else if ( option instanceof CacheMode cacheMode ) {
2406+
storeMode = cacheMode.getJpaStoreMode();
2407+
retrieveMode = cacheMode.getJpaRetrieveMode();
2408+
}
23632409
else if ( option instanceof LockModeType lockModeType ) {
23642410
lockOptions.setLockMode( LockModeTypeHelper.getLockMode( lockModeType ) );
23652411
}

hibernate-core/src/main/java/org/hibernate/loader/ast/internal/ExecutionContextWithSubselectFetchHandler.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,27 @@
99
import org.hibernate.engine.spi.EntityHolder;
1010
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1111
import org.hibernate.engine.spi.SubselectFetch;
12+
import org.hibernate.query.spi.QueryOptions;
1213
import org.hibernate.sql.exec.internal.BaseExecutionContext;
1314

1415
class ExecutionContextWithSubselectFetchHandler extends BaseExecutionContext {
1516

1617
private final SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler;
18+
private final boolean readOnly;
1719

1820
public ExecutionContextWithSubselectFetchHandler(
1921
SharedSessionContractImplementor session,
2022
SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler) {
23+
this( session, subSelectFetchableKeysHandler, false );
24+
}
25+
26+
public ExecutionContextWithSubselectFetchHandler(
27+
SharedSessionContractImplementor session,
28+
SubselectFetch.RegistrationHandler subSelectFetchableKeysHandler,
29+
boolean readOnly) {
2130
super( session );
2231
this.subSelectFetchableKeysHandler = subSelectFetchableKeysHandler;
32+
this.readOnly = readOnly;
2333
}
2434

2535
@Override
@@ -29,4 +39,8 @@ public void registerLoadingEntityHolder(EntityHolder holder) {
2939
}
3040
}
3141

42+
@Override
43+
public QueryOptions getQueryOptions() {
44+
return readOnly ? QueryOptions.READ_ONLY : super.getQueryOptions();
45+
}
3246
}

0 commit comments

Comments
 (0)