/** * process any unreferenced collections and then inspect all known collections, scheduling * creates/removes/updates */ private void flushCollections(EventSource session) throws HibernateException { if (LOG.isTraceEnabled()) { LOG.trace("Processing unreferenced collections"); } List list = IdentityMap.entries(session.getPersistenceContext().getCollectionEntries()); int size = list.size(); for (int i = 0; i < size; i++) { Map.Entry me = (Map.Entry) list.get(i); CollectionEntry ce = (CollectionEntry) me.getValue(); if (!ce.isReached() && !ce.isIgnore()) { Collections.processUnreachableCollection((PersistentCollection) me.getKey(), session); } } // Schedule updates to collections: if (LOG.isTraceEnabled()) { LOG.trace("Scheduling collection removes/(re)creates/updates"); } list = IdentityMap.entries(session.getPersistenceContext().getCollectionEntries()); size = list.size(); ActionQueue actionQueue = session.getActionQueue(); for (int i = 0; i < size; i++) { Map.Entry me = (Map.Entry) list.get(i); PersistentCollection coll = (PersistentCollection) me.getKey(); CollectionEntry ce = (CollectionEntry) me.getValue(); if (ce.isDorecreate()) { session.getInterceptor().onCollectionRecreate(coll, ce.getCurrentKey()); actionQueue.addAction( new CollectionRecreateAction( coll, ce.getCurrentPersister(), ce.getCurrentKey(), session)); } if (ce.isDoremove()) { session.getInterceptor().onCollectionRemove(coll, ce.getLoadedKey()); actionQueue.addAction( new CollectionRemoveAction( coll, ce.getLoadedPersister(), ce.getLoadedKey(), ce.isSnapshotEmpty(coll), session)); } if (ce.isDoupdate()) { session.getInterceptor().onCollectionUpdate(coll, ce.getLoadedKey()); actionQueue.addAction( new CollectionUpdateAction( coll, ce.getLoadedPersister(), ce.getLoadedKey(), ce.isSnapshotEmpty(coll), session)); } } actionQueue.sortCollectionActions(); }
/** * 1. record the collection role that this collection is referenced by 2. decide if the collection * needs deleting/creating/updating (but don't actually schedule the action yet) */ @SuppressWarnings({"JavaDoc"}) private static void prepareCollectionForUpdate( PersistentCollection collection, CollectionEntry entry, SessionFactoryImplementor factory) { if (entry.isProcessed()) { throw new AssertionFailure("collection was processed twice by flush()"); } entry.setProcessed(true); final CollectionPersister loadedPersister = entry.getLoadedPersister(); final CollectionPersister currentPersister = entry.getCurrentPersister(); if (loadedPersister != null || currentPersister != null) { // it is or was referenced _somewhere_ boolean ownerChanged = loadedPersister != currentPersister || // if either its role changed, !currentPersister .getKeyType() .isEqual( // or its key changed entry.getLoadedKey(), entry.getCurrentKey(), factory); if (ownerChanged) { // do a check final boolean orphanDeleteAndRoleChanged = loadedPersister != null && currentPersister != null && loadedPersister.hasOrphanDelete(); if (orphanDeleteAndRoleChanged) { throw new HibernateException( "Don't change the reference to a collection with cascade=\"all-delete-orphan\": " + loadedPersister.getRole()); } // do the work if (currentPersister != null) { entry.setDorecreate(true); // we will need to create new entries } if (loadedPersister != null) { entry.setDoremove(true); // we will need to remove ye olde entries if (entry.isDorecreate()) { LOG.trace("Forcing collection initialization"); collection.forceInitialization(); } } } else if (collection.isDirty()) { // the collection's elements have changed entry.setDoupdate(true); } } }
/** * process any unreferenced collections and then inspect all known collections, scheduling * creates/removes/updates */ @SuppressWarnings("unchecked") private int flushCollections( final EventSource session, final PersistenceContext persistenceContext) throws HibernateException { LOG.trace("Processing unreferenced collections"); final Map.Entry<PersistentCollection, CollectionEntry>[] entries = IdentityMap.concurrentEntries( (Map<PersistentCollection, CollectionEntry>) persistenceContext.getCollectionEntries()); final int count = entries.length; for (Map.Entry<PersistentCollection, CollectionEntry> me : entries) { CollectionEntry ce = me.getValue(); if (!ce.isReached() && !ce.isIgnore()) { Collections.processUnreachableCollection(me.getKey(), session); } } // Schedule updates to collections: LOG.trace("Scheduling collection removes/(re)creates/updates"); ActionQueue actionQueue = session.getActionQueue(); for (Map.Entry<PersistentCollection, CollectionEntry> me : IdentityMap.concurrentEntries( (Map<PersistentCollection, CollectionEntry>) persistenceContext.getCollectionEntries())) { PersistentCollection coll = me.getKey(); CollectionEntry ce = me.getValue(); if (ce.isDorecreate()) { session.getInterceptor().onCollectionRecreate(coll, ce.getCurrentKey()); actionQueue.addAction( new CollectionRecreateAction( coll, ce.getCurrentPersister(), ce.getCurrentKey(), session)); } if (ce.isDoremove()) { session.getInterceptor().onCollectionRemove(coll, ce.getLoadedKey()); actionQueue.addAction( new CollectionRemoveAction( coll, ce.getLoadedPersister(), ce.getLoadedKey(), ce.isSnapshotEmpty(coll), session)); } if (ce.isDoupdate()) { session.getInterceptor().onCollectionUpdate(coll, ce.getLoadedKey()); actionQueue.addAction( new CollectionUpdateAction( coll, ce.getLoadedPersister(), ce.getLoadedKey(), ce.isSnapshotEmpty(coll), session)); } // todo : I'm not sure the !wasInitialized part should really be part of this check if (!coll.wasInitialized() && coll.hasQueuedOperations()) { actionQueue.addAction( new QueuedOperationCollectionAction( coll, ce.getLoadedPersister(), ce.getLoadedKey(), session)); } } actionQueue.sortCollectionActions(); return count; }