/**
   * process cascade save/update at the start of a flush to discover any newly referenced entity
   * that must be passed to saveOrUpdate(), and also apply orphan delete
   */
  private void prepareEntityFlushes(EventSource session, PersistenceContext persistenceContext)
      throws HibernateException {

    LOG.debug("Processing flush-time cascades");

    final Object anything = getAnything();
    // safe from concurrent modification because of how concurrentEntries() is implemented on
    // IdentityMap
    for (Map.Entry<Object, EntityEntry> me : persistenceContext.reentrantSafeEntityEntries()) {
      //		for ( Map.Entry me : IdentityMap.concurrentEntries( persistenceContext.getEntityEntries()
      // ) ) {
      EntityEntry entry = (EntityEntry) me.getValue();
      Status status = entry.getStatus();
      if (status == Status.MANAGED || status == Status.SAVING || status == Status.READ_ONLY) {
        cascadeOnFlush(session, entry.getPersister(), me.getKey(), anything);
      }
    }
  }
  /**
   * 1. detect any dirty entities 2. schedule any entity updates 3. search out any reachable
   * collections
   */
  private int flushEntities(final FlushEvent event, final PersistenceContext persistenceContext)
      throws HibernateException {

    LOG.trace("Flushing entities and processing referenced collections");

    final EventSource source = event.getSession();
    final Iterable<FlushEntityEventListener> flushListeners =
        source
            .getFactory()
            .getServiceRegistry()
            .getService(EventListenerRegistry.class)
            .getEventListenerGroup(EventType.FLUSH_ENTITY)
            .listeners();

    // Among other things, updateReachables() will recursively load all
    // collections that are moving roles. This might cause entities to
    // be loaded.

    // So this needs to be safe from concurrent modification problems.

    final Map.Entry<Object, EntityEntry>[] entityEntries =
        persistenceContext.reentrantSafeEntityEntries();
    final int count = entityEntries.length;

    for (Map.Entry<Object, EntityEntry> me : entityEntries) {

      // Update the status of the object and if necessary, schedule an update

      EntityEntry entry = me.getValue();
      Status status = entry.getStatus();

      if (status != Status.LOADING && status != Status.GONE) {
        final FlushEntityEvent entityEvent = new FlushEntityEvent(source, me.getKey(), entry);
        for (FlushEntityEventListener listener : flushListeners) {
          listener.onFlushEntity(entityEvent);
        }
      }
    }

    source.getActionQueue().sortActions();

    return count;
  }