Skip to content

Commit cf09e04

Browse files
committed
HHH-19278 fix some logic in MultiIdEntityLoaders that just looks wrong
I'm not going to make a habit of "fixing" things I don't have a test for, I promise also various cleanups to MultiIdEntityLoaders and EntityBatchLoaders
1 parent d871b19 commit cf09e04

File tree

7 files changed

+92
-235
lines changed

7 files changed

+92
-235
lines changed

hibernate-core/src/main/java/org/hibernate/engine/internal/BatchFetchQueueHelper.java

Lines changed: 0 additions & 96 deletions
This file was deleted.

hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -931,8 +931,8 @@ public Object proxyFor(EntityPersister persister, EntityKey key, Object impl) th
931931

932932
@Override
933933
public Object proxyFor(Object impl) throws HibernateException {
934-
final EntityEntry e = getEntry( impl );
935-
return e == null ? impl : proxyFor( e.getPersister(), e.getEntityKey(), impl );
934+
final EntityEntry entry = getEntry( impl );
935+
return entry == null ? impl : proxyFor( entry.getPersister(), entry.getEntityKey(), impl );
936936
}
937937

938938
@Override
@@ -1026,15 +1026,12 @@ public Object getLoadedCollectionOwnerOrNull(PersistentCollection<?> collection)
10261026
if ( ce == null || ce.getLoadedPersister() == null ) {
10271027
return null;
10281028
}
1029-
1030-
Object loadedOwner = null;
1031-
// TODO: an alternative is to check if the owner has changed; if it hasn't then
1032-
// return collection.getOwner()
1033-
final Object entityId = getLoadedCollectionOwnerIdOrNull( ce );
1034-
if ( entityId != null ) {
1035-
loadedOwner = getCollectionOwner( entityId, ce.getLoadedPersister() );
1029+
else {
1030+
// TODO: an alternative is to check if the owner has changed; if it hasn't then
1031+
// return collection.getOwner()
1032+
final Object entityId = getLoadedCollectionOwnerIdOrNull( ce );
1033+
return entityId != null ? getCollectionOwner( entityId, ce.getLoadedPersister() ) : null;
10361034
}
1037-
return loadedOwner;
10381035
}
10391036

10401037
@Override
@@ -1052,9 +1049,12 @@ private Object getLoadedCollectionOwnerIdOrNull(CollectionEntry ce) {
10521049
if ( ce == null || ce.getLoadedKey() == null || ce.getLoadedPersister() == null ) {
10531050
return null;
10541051
}
1055-
// TODO: an alternative is to check if the owner has changed; if it hasn't then
1056-
// get the ID from collection.getOwner()
1057-
return ce.getLoadedPersister().getCollectionType().getIdOfOwnerOrNull( ce.getLoadedKey(), session );
1052+
else {
1053+
// TODO: an alternative is to check if the owner has changed; if it hasn't then
1054+
// get the ID from collection.getOwner()
1055+
return ce.getLoadedPersister().getCollectionType()
1056+
.getIdOfOwnerOrNull( ce.getLoadedKey(), session );
1057+
}
10581058
}
10591059

10601060
@Override

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

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88
import org.hibernate.LockMode;
99
import org.hibernate.LockOptions;
1010
import org.hibernate.engine.jdbc.spi.JdbcServices;
11+
import org.hibernate.engine.spi.BatchFetchQueue;
1112
import org.hibernate.engine.spi.EntityKey;
13+
import org.hibernate.engine.spi.PersistenceContext;
1214
import org.hibernate.engine.spi.SessionFactoryImplementor;
1315
import org.hibernate.event.spi.EventSource;
1416
import org.hibernate.loader.ast.spi.MultiIdEntityLoader;
@@ -164,11 +166,32 @@ protected static LockOptions lockOptions(MultiIdLoadOptions loadOptions) {
164166

165167
protected abstract int maxBatchSize(Object[] ids, MultiIdLoadOptions loadOptions);
166168

167-
protected abstract void handleResults(
169+
protected void handleResults(
168170
MultiIdLoadOptions loadOptions,
169171
EventSource session,
170172
List<Integer> elementPositionsLoadedByBatch,
171-
List<Object> result);
173+
List<Object> results) {
174+
final PersistenceContext persistenceContext = session.getPersistenceContext();
175+
for ( Integer position : elementPositionsLoadedByBatch ) {
176+
// the element value at this position in the results List should be
177+
// the EntityKey for that entity - reuse it
178+
final EntityKey entityKey = (EntityKey) results.get( position );
179+
session.getPersistenceContextInternal().getBatchFetchQueue().removeBatchLoadableEntityKey( entityKey );
180+
final Object entity = persistenceContext.getEntity( entityKey );
181+
final Object result;
182+
if ( entity == null
183+
// the entity is locally deleted, and the options ask that we not return such entities
184+
|| !loadOptions.isReturnOfDeletedEntitiesEnabled()
185+
&& persistenceContext.getEntry( entity ).getStatus().isDeletedOrGone() ) {
186+
result = null;
187+
}
188+
else {
189+
result = persistenceContext.proxyFor( entity );
190+
}
191+
results.set( position, result );
192+
}
193+
}
194+
172195

173196
protected abstract void loadEntitiesById(
174197
List<Object> idsInBatch,
@@ -192,39 +215,36 @@ private boolean isLoadFromCaches(
192215
MultiIdLoadOptions loadOptions,
193216
EntityKey entityKey,
194217
LockOptions lockOptions,
195-
List<Object> result, int i,
218+
List<Object> results, int i,
196219
EventSource session) {
197-
Object managedEntity = null;
198220

199221
if ( loadOptions.isSessionCheckingEnabled() ) {
200222
// look for it in the Session first
201-
final PersistenceContextEntry persistenceContextEntry =
223+
final PersistenceContextEntry entry =
202224
loadFromSessionCache( entityKey, lockOptions, GET, session );
203-
managedEntity = persistenceContextEntry.entity();
204-
205-
if ( managedEntity != null
206-
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
207-
&& !persistenceContextEntry.isManaged() ) {
208-
// put a null in the result
209-
result.add( i, null );
225+
final Object entity = entry.entity();
226+
if ( entity != null ) {
227+
// put a null in the results
228+
final Object result =
229+
loadOptions.isReturnOfDeletedEntitiesEnabled()
230+
|| entry.isManaged()
231+
? entity : null;
232+
results.add( i, result );
210233
return true;
211234
}
212235
}
213236

214-
if ( managedEntity == null
215-
&& loadOptions.isSecondLevelCacheCheckingEnabled() ) {
216-
// look for it in the SessionFactory
217-
final EntityPersister persister = getLoadable().getEntityPersister();
218-
managedEntity = session.loadFromSecondLevelCache( persister, entityKey, null, lockOptions.getLockMode() );
237+
if ( loadOptions.isSecondLevelCacheCheckingEnabled() ) {
238+
// look for it in the second-level cache
239+
final Object entity =
240+
loadFromSecondLevelCache( entityKey, lockOptions, session );
241+
if ( entity != null ) {
242+
results.add( i, entity );
243+
return true;
244+
}
219245
}
220246

221-
if ( managedEntity != null ) {
222-
result.add( i, managedEntity );
223-
return true;
224-
}
225-
else {
226-
return false;
227-
}
247+
return false;
228248
}
229249

230250
protected List<T> unorderedMultiLoad(
@@ -238,6 +258,16 @@ protected List<T> unorderedMultiLoad(
238258
(position, entityKey, resolvedRef) -> result.add( (T) resolvedRef ) );
239259
if ( !isEmpty( unresolvableIds ) ) {
240260
loadEntitiesWithUnresolvedIds( loadOptions, lockOptions, session, unresolvableIds, result );
261+
final BatchFetchQueue batchFetchQueue = session.getPersistenceContextInternal().getBatchFetchQueue();
262+
final EntityPersister persister = getLoadable().getEntityPersister();
263+
for ( Object id : unresolvableIds ) {
264+
// skip any of the null padded ids
265+
// (actually we could probably even break on the first null)
266+
if ( id != null ) {
267+
// found or not, remove the key from the batch-fetch queue
268+
batchFetchQueue.removeBatchLoadableEntityKey( session.generateEntityKey( id, persister ) );
269+
}
270+
}
241271
}
242272
return result;
243273
}
@@ -247,7 +277,7 @@ protected abstract void loadEntitiesWithUnresolvedIds(
247277
LockOptions lockOptions,
248278
EventSource session,
249279
Object[] unresolvableIds,
250-
List<T> result);
280+
List<T> results);
251281

252282
protected final <R> Object[] resolveInCachesIfEnabled(
253283
Object[] ids,
@@ -259,7 +289,7 @@ protected final <R> Object[] resolveInCachesIfEnabled(
259289
// the user requested that we exclude ids corresponding to already managed
260290
// entities from the generated load SQL. So here we will iterate all
261291
// incoming id values and see whether it corresponds to an existing
262-
// entity associated with the PC. If it does, we add it to the result
292+
// entity associated with the PC. If it does, we add it to the results
263293
// list immediately and remove its id from the group of ids to load.
264294
// we'll load all of them from the database
265295
? resolveInCaches( ids, loadOptions, lockOptions, session, resolutionConsumer )
@@ -319,14 +349,14 @@ private <R> List<Object> loadFromCaches(
319349
EventSource session) {
320350

321351
// look for it in the Session first
322-
final PersistenceContextEntry persistenceContextEntry =
352+
final PersistenceContextEntry entry =
323353
loadFromSessionCache( entityKey, lockOptions, GET, session );
324354
final Object sessionEntity;
325355
if ( loadOptions.isSessionCheckingEnabled() ) {
326-
sessionEntity = persistenceContextEntry.entity();
356+
sessionEntity = entry.entity();
327357
if ( sessionEntity != null
328358
&& !loadOptions.isReturnOfDeletedEntitiesEnabled()
329-
&& !persistenceContextEntry.isManaged() ) {
359+
&& !entry.isManaged() ) {
330360
resolutionConsumer.consume( i, entityKey, null );
331361
return unresolvedIds;
332362
}
@@ -335,13 +365,10 @@ private <R> List<Object> loadFromCaches(
335365
sessionEntity = null;
336366
}
337367

338-
final Object cachedEntity;
339-
if ( sessionEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled() ) {
340-
cachedEntity = session.loadFromSecondLevelCache( getLoadable().getEntityPersister(), entityKey, null, lockOptions.getLockMode() );
341-
}
342-
else {
343-
cachedEntity = sessionEntity;
344-
}
368+
final Object cachedEntity =
369+
sessionEntity == null && loadOptions.isSecondLevelCacheCheckingEnabled()
370+
? loadFromSecondLevelCache( entityKey, lockOptions, session )
371+
: sessionEntity;
345372

346373
if ( cachedEntity != null ) {
347374
//noinspection unchecked
@@ -356,4 +383,8 @@ private <R> List<Object> loadFromCaches(
356383
return unresolvedIds;
357384
}
358385

386+
private Object loadFromSecondLevelCache(EntityKey entityKey, LockOptions lockOptions, EventSource session) {
387+
final EntityPersister persister = getLoadable().getEntityPersister();
388+
return session.loadFromSecondLevelCache( persister, entityKey, null, lockOptions.getLockMode() );
389+
}
359390
}

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

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.util.Locale;
1010

1111
import org.hibernate.LockOptions;
12+
import org.hibernate.engine.spi.BatchFetchQueue;
1213
import org.hibernate.engine.spi.LoadQueryInfluencers;
1314
import org.hibernate.engine.spi.SharedSessionContractImplementor;
1415
import org.hibernate.internal.build.AllowReflection;
@@ -17,14 +18,14 @@
1718
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
1819
import org.hibernate.metamodel.mapping.EntityMappingType;
1920
import org.hibernate.metamodel.mapping.JdbcMapping;
21+
import org.hibernate.persister.entity.EntityPersister;
2022
import org.hibernate.query.spi.QueryOptions;
2123
import org.hibernate.sql.ast.tree.expression.JdbcParameter;
2224
import org.hibernate.sql.ast.tree.select.SelectStatement;
2325
import org.hibernate.sql.exec.internal.JdbcParameterImpl;
2426
import org.hibernate.sql.exec.spi.JdbcOperationQuerySelect;
2527
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
2628

27-
import static org.hibernate.engine.internal.BatchFetchQueueHelper.removeBatchLoadableEntityKey;
2829
import static org.hibernate.loader.ast.internal.MultiKeyLoadHelper.trimIdBatch;
2930
import static org.hibernate.loader.ast.internal.MultiKeyLoadLogging.MULTI_KEY_LOAD_LOGGER;
3031

@@ -40,7 +41,6 @@ public class EntityBatchLoaderArrayParam<T>
4041
implements SqlArrayMultiKeyLoader {
4142
private final int domainBatchSize;
4243

43-
private final LoadQueryInfluencers loadQueryInfluencers;
4444
private final BasicEntityIdentifierMapping identifierMapping;
4545
private final JdbcMapping arrayJdbcMapping;
4646
private final JdbcParameter jdbcParameter;
@@ -64,7 +64,6 @@ public EntityBatchLoaderArrayParam(
6464
EntityMappingType entityDescriptor,
6565
LoadQueryInfluencers loadQueryInfluencers) {
6666
super( entityDescriptor, loadQueryInfluencers );
67-
this.loadQueryInfluencers = loadQueryInfluencers;
6867
this.domainBatchSize = domainBatchSize;
6968

7069
if ( MULTI_KEY_LOAD_LOGGER.isDebugEnabled() ) {
@@ -133,10 +132,12 @@ protected void initializeEntities(
133132
getLoadable().getEntityName(), id, Arrays.toString(idsToInitialize) );
134133
}
135134

135+
final BatchFetchQueue batchFetchQueue = session.getPersistenceContextInternal().getBatchFetchQueue();
136+
final EntityPersister persister = getLoadable().getEntityPersister();
136137
for ( Object initializedId : idsToInitialize ) {
137138
if ( initializedId != null ) {
138139
// found or not, remove the key from the batch-fetch queue
139-
removeBatchLoadableEntityKey( initializedId, getLoadable(), session );
140+
batchFetchQueue.removeBatchLoadableEntityKey( session.generateEntityKey( initializedId, persister ) );
140141
}
141142
}
142143

0 commit comments

Comments
 (0)