55package org .hibernate .event .internal ;
66
77import java .lang .invoke .MethodHandles ;
8+ import java .util .Map ;
89
910import org .hibernate .HibernateException ;
1011import org .hibernate .Interceptor ;
1516import org .hibernate .collection .spi .PersistentCollection ;
1617import org .hibernate .engine .internal .Cascade ;
1718import org .hibernate .engine .internal .CascadePoint ;
18- import org .hibernate .engine .spi .ActionQueue ;
1919import org .hibernate .engine .spi .CascadingActions ;
2020import org .hibernate .engine .spi .CollectionEntry ;
2121import org .hibernate .engine .spi .CollectionKey ;
@@ -143,30 +143,30 @@ void checkForTransientReferences(EventSource session, PersistenceContext persist
143143 // processed, so that all entities which will be persisted are
144144 // persistent when we do the check (I wonder if we could move this
145145 // into Nullability, instead of abusing the Cascade infrastructure)
146- for ( var me : persistenceContext .reentrantSafeEntityEntries () ) {
147- final var entry = me .getValue ();
146+ for ( var entryEntry : persistenceContext .reentrantSafeEntityEntries () ) {
147+ final var entry = entryEntry .getValue ();
148148 if ( checkable ( entry ) ) {
149149 Cascade .cascade (
150150 CascadingActions .CHECK_ON_FLUSH ,
151151 CascadePoint .BEFORE_FLUSH ,
152152 session ,
153153 entry .getPersister (),
154- me .getKey (),
154+ entryEntry .getKey (),
155155 null
156156 );
157157 }
158158 }
159159 }
160160
161161 private static boolean flushable (EntityEntry entry ) {
162- final Status status = entry .getStatus ();
162+ final var status = entry .getStatus ();
163163 return status == Status .MANAGED
164164 || status == Status .SAVING
165165 || status == Status .READ_ONLY ; // debatable, see HHH-19398
166166 }
167167
168168 private static boolean checkable (EntityEntry entry ) {
169- final Status status = entry .getStatus ();
169+ final var status = entry .getStatus ();
170170 return status == Status .MANAGED
171171 || status == Status .SAVING ;
172172 }
@@ -228,7 +228,7 @@ private int flushEntities(final FlushEvent event, final PersistenceContext persi
228228 for ( var me : entityEntries ) {
229229 // Update the status of the object and if necessary, schedule an update
230230 final var entry = me .getValue ();
231- final Status status = entry .getStatus ();
231+ final var status = entry .getStatus ();
232232 if ( status != Status .LOADING && status != Status .GONE ) {
233233 entityEvent = createOrReuseEventInstance ( entityEvent , source , me .getKey (), entry );
234234 entityEvent .setInstanceGenerationId ( ++eventGenerationId );
@@ -270,74 +270,62 @@ private int flushCollections(final EventSource session, final PersistenceContext
270270 throws HibernateException {
271271 LOG .trace ( "Processing unreferenced collections" );
272272 final var collectionEntries = persistenceContext .getCollectionEntries ();
273- final int count ;
274- if ( collectionEntries == null ) {
275- count = 0 ;
276- }
277- else {
278- count = collectionEntries .size ();
279- final var identityMap =
280- (InstanceIdentityMap <PersistentCollection <?>, CollectionEntry >)
281- collectionEntries ;
282- for ( var me : identityMap .toArray () ) {
283- final var ce = me .getValue ();
284- if ( !ce .isReached () && !ce .isIgnore () ) {
285- processUnreachableCollection ( me .getKey (), session );
286- }
287- }
288- }
273+ final int count = processUnreachableCollections ( session , collectionEntries );
289274
290275 // Schedule updates to collections:
291276
292277 LOG .trace ( "Scheduling collection removes/(re)creates/updates" );
293278 final var actionQueue = session .getActionQueue ();
294279 final var interceptor = session .getInterceptor ();
295280 persistenceContext .forEachCollectionEntry (
296- (coll , ce ) -> {
297- if ( ce .isDorecreate () ) {
298- interceptor .onCollectionRecreate ( coll , ce .getCurrentKey () );
281+ (collection , collectionEntry ) -> {
282+ if ( collectionEntry .isDorecreate () ) {
283+ final var currentKey = collectionEntry .getCurrentKey ();
284+ interceptor .onCollectionRecreate ( collection , currentKey );
299285 actionQueue .addAction (
300286 new CollectionRecreateAction (
301- coll ,
302- ce .getCurrentPersister (),
303- ce . getCurrentKey () ,
287+ collection ,
288+ collectionEntry .getCurrentPersister (),
289+ currentKey ,
304290 session
305291 )
306292 );
307293 }
308- if ( ce .isDoremove () ) {
309- interceptor .onCollectionRemove ( coll , ce .getLoadedKey () );
310- if ( !skipRemoval ( session , ce .getLoadedPersister (), ce .getLoadedKey () ) ) {
294+ if ( collectionEntry .isDoremove () ) {
295+ final var loadedKey = collectionEntry .getLoadedKey ();
296+ interceptor .onCollectionRemove ( collection , loadedKey );
297+ if ( !skipRemoval ( session , collectionEntry .getLoadedPersister (), loadedKey ) ) {
311298 actionQueue .addAction (
312299 new CollectionRemoveAction (
313- coll ,
314- ce .getLoadedPersister (),
315- ce . getLoadedKey () ,
316- ce .isSnapshotEmpty ( coll ),
300+ collection ,
301+ collectionEntry .getLoadedPersister (),
302+ loadedKey ,
303+ collectionEntry .isSnapshotEmpty ( collection ),
317304 session
318305 )
319306 );
320307 }
321308 }
322- if ( ce .isDoupdate () ) {
323- interceptor .onCollectionUpdate ( coll , ce .getLoadedKey () );
309+ if ( collectionEntry .isDoupdate () ) {
310+ final var loadedKey = collectionEntry .getLoadedKey ();
311+ interceptor .onCollectionUpdate ( collection , loadedKey );
324312 actionQueue .addAction (
325313 new CollectionUpdateAction (
326- coll ,
327- ce .getLoadedPersister (),
328- ce . getLoadedKey () ,
329- ce .isSnapshotEmpty ( coll ),
314+ collection ,
315+ collectionEntry .getLoadedPersister (),
316+ loadedKey ,
317+ collectionEntry .isSnapshotEmpty ( collection ),
330318 session
331319 )
332320 );
333321 }
334322 // todo : I'm not sure the !wasInitialized part should really be part of this check
335- if ( !coll .wasInitialized () && coll .hasQueuedOperations () ) {
323+ if ( !collection .wasInitialized () && collection .hasQueuedOperations () ) {
336324 actionQueue .addAction (
337325 new QueuedOperationCollectionAction (
338- coll ,
339- ce .getLoadedPersister (),
340- ce .getLoadedKey (),
326+ collection ,
327+ collectionEntry .getLoadedPersister (),
328+ collectionEntry .getLoadedKey (),
341329 session
342330 )
343331 );
@@ -349,6 +337,27 @@ private int flushCollections(final EventSource session, final PersistenceContext
349337 return count ;
350338 }
351339
340+ private static int processUnreachableCollections (
341+ EventSource session ,
342+ Map <PersistentCollection <?>, CollectionEntry > collectionEntries ) {
343+ if ( collectionEntries == null ) {
344+ return 0 ;
345+ }
346+ else {
347+ final int count = collectionEntries .size ();
348+ final var identityMap =
349+ (InstanceIdentityMap <PersistentCollection <?>, CollectionEntry >)
350+ collectionEntries ;
351+ for ( var entry : identityMap .toArray () ) {
352+ final var collectionEntry = entry .getValue ();
353+ if ( !collectionEntry .isReached () && !collectionEntry .isIgnore () ) {
354+ processUnreachableCollection ( entry .getKey (), session );
355+ }
356+ }
357+ return count ;
358+ }
359+ }
360+
352361 /**
353362 * Execute all SQL (and second-level cache updates) in a special order so that foreign-key constraints cannot
354363 * be violated: <ol>
@@ -375,7 +384,7 @@ protected void performExecutions(EventSource session) {
375384 persistenceContext .setFlushing ( true );
376385 // we need to lock the collection caches before executing entity inserts/updates
377386 // in order to account for bidirectional associations
378- final ActionQueue actionQueue = session .getActionQueue ();
387+ final var actionQueue = session .getActionQueue ();
379388 actionQueue .prepareActions ();
380389 actionQueue .executeActions ();
381390 }
@@ -410,26 +419,27 @@ protected void postFlush(SessionImplementor session) throws HibernateException {
410419 persistenceContext .forEachCollectionEntry (
411420 (persistentCollection , collectionEntry ) -> {
412421 collectionEntry .postFlush ( persistentCollection );
413- final Object key ;
414- if ( collectionEntry .getLoadedPersister () == null || ( key = collectionEntry .getLoadedKey () ) == null ) {
422+ final var loadedPersister = collectionEntry .getLoadedPersister ();
423+ final Object key = collectionEntry .getLoadedKey ();
424+ if ( loadedPersister != null && key != null ) {
425+ //otherwise recreate the mapping between the collection and its key
426+ final var collectionKey = new CollectionKey ( loadedPersister , key );
427+ persistenceContext .addCollectionByKey ( collectionKey , persistentCollection );
428+ }
429+ else {
415430 //if the collection is dereferenced, unset its session reference and remove from the session cache
416431 //iter.remove(); //does not work, since the entrySet is not backed by the set
417432 persistentCollection .unsetSession ( session );
418433 persistenceContext .removeCollectionEntry ( persistentCollection );
419434 }
420- else {
421- //otherwise recreate the mapping between the collection and its key
422- final CollectionKey collectionKey =
423- new CollectionKey ( collectionEntry .getLoadedPersister (), key );
424- persistenceContext .addCollectionByKey ( collectionKey , persistentCollection );
425- }
426435 },
427436 true
428437 );
429438 }
430439
431440 protected void postPostFlush (SessionImplementor session ) {
432- session .getInterceptor ().postFlush ( session .getPersistenceContextInternal ().managedEntitiesIterator () );
441+ session .getInterceptor ()
442+ .postFlush ( session .getPersistenceContextInternal ().managedEntitiesIterator () );
433443 }
434444
435445}
0 commit comments