protected boolean handleInterception(FlushEntityEvent event) { SessionImplementor session = event.getSession(); EntityEntry entry = event.getEntityEntry(); EntityPersister persister = entry.getPersister(); Object entity = event.getEntity(); // give the Interceptor a chance to modify property values final Object[] values = event.getPropertyValues(); final boolean intercepted = invokeInterceptor(session, entity, entry, values, persister); // now we might need to recalculate the dirtyProperties array if (intercepted && event.isDirtyCheckPossible() && !event.isDirtyCheckHandledByInterceptor()) { int[] dirtyProperties; if (event.hasDatabaseSnapshot()) { dirtyProperties = persister.findModified(event.getDatabaseSnapshot(), values, entity, session); } else { dirtyProperties = persister.findDirty(values, entry.getLoadedState(), entity, session); } event.setDirtyProperties(dirtyProperties); } return intercepted; }
/** Perform a dirty check, and attach the results to the event */ protected void dirtyCheck(FlushEntityEvent event) throws HibernateException { final Object entity = event.getEntity(); final Object[] values = event.getPropertyValues(); final SessionImplementor session = event.getSession(); final EntityEntry entry = event.getEntityEntry(); final EntityPersister persister = entry.getPersister(); final Serializable id = entry.getId(); final Object[] loadedState = entry.getLoadedState(); int[] dirtyProperties = session .getInterceptor() .findDirty( entity, id, values, loadedState, persister.getPropertyNames(), persister.getPropertyTypes()); event.setDatabaseSnapshot(null); final boolean interceptorHandledDirtyCheck; boolean cannotDirtyCheck; if (dirtyProperties == null) { // Interceptor returned null, so do the dirtycheck ourself, if possible interceptorHandledDirtyCheck = false; cannotDirtyCheck = loadedState == null; // object loaded by update() if (!cannotDirtyCheck) { // dirty check against the usual snapshot of the entity dirtyProperties = persister.findDirty(values, loadedState, entity, session); } else if (entry.getStatus() == Status.DELETED && !event.getEntityEntry().isModifiableEntity()) { // A non-modifiable (e.g., read-only or immutable) entity needs to be have // references to transient entities set to null before being deleted. No other // fields should be updated. if (values != entry.getDeletedState()) { throw new IllegalStateException( "Entity has status Status.DELETED but values != entry.getDeletedState"); } // Even if loadedState == null, we can dirty-check by comparing currentState and // entry.getDeletedState() because the only fields to be updated are those that // refer to transient entities that are being set to null. // - currentState contains the entity's current property values. // - entry.getDeletedState() contains the entity's current property values with // references to transient entities set to null. // - dirtyProperties will only contain properties that refer to transient entities final Object[] currentState = persister.getPropertyValues(event.getEntity(), event.getSession().getEntityMode()); dirtyProperties = persister.findDirty(entry.getDeletedState(), currentState, entity, session); cannotDirtyCheck = false; } else { // dirty check against the database snapshot, if possible/necessary final Object[] databaseSnapshot = getDatabaseSnapshot(session, persister, id); if (databaseSnapshot != null) { dirtyProperties = persister.findModified(databaseSnapshot, values, entity, session); cannotDirtyCheck = false; event.setDatabaseSnapshot(databaseSnapshot); } } } else { // the Interceptor handled the dirty checking cannotDirtyCheck = false; interceptorHandledDirtyCheck = true; } logDirtyProperties(id, dirtyProperties, persister); event.setDirtyProperties(dirtyProperties); event.setDirtyCheckHandledByInterceptor(interceptorHandledDirtyCheck); event.setDirtyCheckPossible(!cannotDirtyCheck); }