/** * 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; }