/**
   * 1. Recreate the collection key -> collection map 2. rebuild the collection entries 3. call
   * Interceptor.postFlush()
   */
  protected void postFlush(SessionImplementor session) throws HibernateException {

    LOG.trace("Post flush");

    final PersistenceContext persistenceContext = session.getPersistenceContext();
    persistenceContext.getCollectionsByKey().clear();

    // the database has changed now, so the subselect results need to be invalidated
    // the batch fetching queues should also be cleared - especially the collection batch fetching
    // one
    persistenceContext.getBatchFetchQueue().clear();

    for (Map.Entry<PersistentCollection, CollectionEntry> me :
        IdentityMap.concurrentEntries(persistenceContext.getCollectionEntries())) {
      CollectionEntry collectionEntry = me.getValue();
      PersistentCollection persistentCollection = me.getKey();
      collectionEntry.postFlush(persistentCollection);
      if (collectionEntry.getLoadedPersister() == null) {
        // if the collection is dereferenced, unset its session reference and remove from the
        // session cache
        // iter.remove(); //does not work, since the entrySet is not backed by the set
        persistentCollection.unsetSession(session);
        persistenceContext.getCollectionEntries().remove(persistentCollection);
      } else {
        // otherwise recreate the mapping between the collection and its key
        CollectionKey collectionKey =
            new CollectionKey(collectionEntry.getLoadedPersister(), collectionEntry.getLoadedKey());
        persistenceContext.getCollectionsByKey().put(collectionKey, persistentCollection);
      }
    }
  }
  /**
   * 1. Recreate the collection key -> collection map 2. rebuild the collection entries 3. call
   * Interceptor.postFlush()
   */
  protected void postFlush(SessionImplementor session) throws HibernateException {

    LOG.trace("Post flush");

    final PersistenceContext persistenceContext = session.getPersistenceContext();
    persistenceContext.getCollectionsByKey().clear();
    persistenceContext
        .getBatchFetchQueue()
        .clearSubselects(); // the database has changed now, so the subselect results need to be
                            // invalidated

    Iterator iter = persistenceContext.getCollectionEntries().entrySet().iterator();
    while (iter.hasNext()) {
      Map.Entry me = (Map.Entry) iter.next();
      CollectionEntry collectionEntry = (CollectionEntry) me.getValue();
      PersistentCollection persistentCollection = (PersistentCollection) me.getKey();
      collectionEntry.postFlush(persistentCollection);
      if (collectionEntry.getLoadedPersister() == null) {
        // if the collection is dereferenced, remove from the session cache
        // iter.remove(); //does not work, since the entrySet is not backed by the set
        persistenceContext.getCollectionEntries().remove(persistentCollection);
      } else {
        // otherwise recreate the mapping between the collection and its key
        CollectionKey collectionKey =
            new CollectionKey(collectionEntry.getLoadedPersister(), collectionEntry.getLoadedKey());
        persistenceContext.getCollectionsByKey().put(collectionKey, persistentCollection);
      }
    }

    session.getInterceptor().postFlush(new LazyIterator(persistenceContext.getEntitiesByKey()));
  }
  /** Initialize the flags of the CollectionEntry, including the dirty check. */
  private void prepareCollectionFlushes(PersistenceContext persistenceContext)
      throws HibernateException {

    // Initialize dirty flags for arrays + collections with composite elements
    // and reset reached, doupdate, etc.

    LOG.debug("Dirty checking collections");

    for (Map.Entry<PersistentCollection, CollectionEntry> entry :
        IdentityMap.concurrentEntries(
            (Map<PersistentCollection, CollectionEntry>)
                persistenceContext.getCollectionEntries())) {
      entry.getValue().preFlush(entry.getKey());
    }
  }
 @SuppressWarnings(value = {"unchecked"})
 private void logFlushResults(FlushEvent event) {
   if (!LOG.isDebugEnabled()) {
     return;
   }
   final EventSource session = event.getSession();
   final PersistenceContext persistenceContext = session.getPersistenceContext();
   LOG.debugf(
       "Flushed: %s insertions, %s updates, %s deletions to %s objects",
       session.getActionQueue().numberOfInsertions(),
       session.getActionQueue().numberOfUpdates(),
       session.getActionQueue().numberOfDeletions(),
       persistenceContext.getNumberOfManagedEntities());
   LOG.debugf(
       "Flushed: %s (re)creations, %s updates, %s removals to %s collections",
       session.getActionQueue().numberOfCollectionCreations(),
       session.getActionQueue().numberOfCollectionUpdates(),
       session.getActionQueue().numberOfCollectionRemovals(),
       persistenceContext.getCollectionEntries().size());
   new EntityPrinter(session.getFactory())
       .toString(persistenceContext.getEntitiesByKey().entrySet());
 }
  /**
   * 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;
  }