88import org .hibernate .LockMode ;
99import org .hibernate .LockOptions ;
1010import org .hibernate .engine .jdbc .spi .JdbcServices ;
11+ import org .hibernate .engine .spi .BatchFetchQueue ;
1112import org .hibernate .engine .spi .EntityKey ;
13+ import org .hibernate .engine .spi .PersistenceContext ;
1214import org .hibernate .engine .spi .SessionFactoryImplementor ;
1315import org .hibernate .event .spi .EventSource ;
1416import 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}
0 commit comments