*/
protected void dirtyCheck(final 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()
);
if ( dirtyProperties == null ) {
if(entity instanceof SelfDirtinessTracker) {
if(((SelfDirtinessTracker) entity).$$_hibernate_hasDirtyAttributes()) {
dirtyProperties = persister.resolveAttributeIndexes(((SelfDirtinessTracker) entity).$$_hibernate_getDirtyAttributes());
}
}
else {
// see if the custom dirtiness strategy can tell us...
class DirtyCheckContextImpl implements CustomEntityDirtinessStrategy.DirtyCheckContext {
int[] found = null;
@Override
public void doDirtyChecking(CustomEntityDirtinessStrategy.AttributeChecker attributeChecker) {
found = new DirtyCheckAttributeInfoImpl( event ).visitAttributes( attributeChecker );
if ( found != null && found.length == 0 ) {
found = null;
}
}
}
DirtyCheckContextImpl context = new DirtyCheckContextImpl();
session.getFactory().getCustomEntityDirtinessStrategy().findDirty(
entity,
persister,
(Session) session,
context
);
dirtyProperties = context.found;
}
}
event.setDatabaseSnapshot(null);
final boolean interceptorHandledDirtyCheck;
boolean cannotDirtyCheck;
if ( dirtyProperties==null ) {
// Interceptor returned null, so do the dirtycheck ourself, if possible
try {
session.getEventListenerManager().dirtyCalculationStart();
interceptorHandledDirtyCheck = false;
// object loaded by update()
cannotDirtyCheck = loadedState==null;
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() );
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);
}
}
}
finally {
session.getEventListenerManager().dirtyCalculationEnd( dirtyProperties != null );
}
}
else {
// the Interceptor handled the dirty checking
cannotDirtyCheck = false;