use of org.hibernate.engine.spi.SelfDirtinessTracker in project hibernate-orm by hibernate.
the class AbstractSaveEventListener method saveWithGeneratedId.
/**
* Prepares the save call using a newly generated id.
*
* @param entity The entity to be saved
* @param entityName The entity-name for the entity to be saved
* @param anything Generally cascade-specific information.
* @param source The session which is the source of this save event.
* @param requiresImmediateIdAccess does the event context require
* access to the identifier immediately after execution of this method (if
* not, post-insert style id generators may be postponed if we are outside
* a transaction).
*
* @return The id used to save the entity; may be null depending on the
* type of id generator used and the requiresImmediateIdAccess value
*/
protected Serializable saveWithGeneratedId(Object entity, String entityName, Object anything, EventSource source, boolean requiresImmediateIdAccess) {
callbackRegistry.preCreate(entity);
if (entity instanceof SelfDirtinessTracker) {
((SelfDirtinessTracker) entity).$$_hibernate_clearDirtyAttributes();
}
EntityPersister persister = source.getEntityPersister(entityName, entity);
Serializable generatedId = persister.getIdentifierGenerator().generate(source, entity);
if (generatedId == null) {
throw new IdentifierGenerationException("null id generated for:" + entity.getClass());
} else if (generatedId == IdentifierGeneratorHelper.SHORT_CIRCUIT_INDICATOR) {
return source.getIdentifier(entity);
} else if (generatedId == IdentifierGeneratorHelper.POST_INSERT_INDICATOR) {
return performSave(entity, null, persister, true, anything, source, requiresImmediateIdAccess);
} else {
// TODO: define toString()s for generators
if (LOG.isDebugEnabled()) {
LOG.debugf("Generated identifier: %s, using strategy: %s", persister.getIdentifierType().toLoggableString(generatedId, source.getFactory()), persister.getIdentifierGenerator().getClass().getName());
}
return performSave(entity, generatedId, persister, false, anything, source, true);
}
}
use of org.hibernate.engine.spi.SelfDirtinessTracker in project hibernate-orm by hibernate.
the class DefaultFlushEntityEventListener method dirtyCheck.
/**
* Perform a dirty check, and attach the results to the event
*/
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()) {
int[] dirty = persister.resolveAttributeIndexes(((SelfDirtinessTracker) entity).$$_hibernate_getDirtyAttributes());
// HHH-12051 - filter non-updatable attributes
// TODO: add Updateability to EnhancementContext and skip dirty tracking of those attributes
int count = 0;
for (int i : dirty) {
if (persister.getPropertyUpdateability()[i]) {
dirty[count++] = i;
}
}
dirtyProperties = count == 0 ? ArrayHelper.EMPTY_INT_ARRAY : count == dirty.length ? dirty : Arrays.copyOf(dirty, count);
} else {
dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
}
} else {
// see if the custom dirtiness strategy can tell us...
class DirtyCheckContextImpl implements CustomEntityDirtinessStrategy.DirtyCheckContext {
private int[] found;
@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, 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()) {
// 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;
interceptorHandledDirtyCheck = true;
}
logDirtyProperties(id, dirtyProperties, persister);
event.setDirtyProperties(dirtyProperties);
event.setDirtyCheckHandledByInterceptor(interceptorHandledDirtyCheck);
event.setDirtyCheckPossible(!cannotDirtyCheck);
}
use of org.hibernate.engine.spi.SelfDirtinessTracker in project hibernate-orm by hibernate.
the class EnhancerTestUtils method checkDirtyTracking.
/**
* compares the dirty fields of an entity with a set of expected values
*/
public static void checkDirtyTracking(Object entityInstance, String... dirtyFields) {
SelfDirtinessTracker selfDirtinessTracker = (SelfDirtinessTracker) entityInstance;
assertEquals(dirtyFields.length > 0, selfDirtinessTracker.$$_hibernate_hasDirtyAttributes());
String[] tracked = selfDirtinessTracker.$$_hibernate_getDirtyAttributes();
assertEquals(dirtyFields.length, tracked.length);
assertTrue(Arrays.asList(tracked).containsAll(Arrays.asList(dirtyFields)));
}
use of org.hibernate.engine.spi.SelfDirtinessTracker in project hibernate-orm by hibernate.
the class LazyAttributeLoadingInterceptor method takeCollectionSizeSnapshot.
//
private void takeCollectionSizeSnapshot(Object target, String fieldName, Object value) {
if (value != null && value instanceof Collection && target instanceof SelfDirtinessTracker) {
CollectionTracker tracker = ((SelfDirtinessTracker) target).$$_hibernate_getCollectionTracker();
if (tracker == null) {
((SelfDirtinessTracker) target).$$_hibernate_clearDirtyAttributes();
tracker = ((SelfDirtinessTracker) target).$$_hibernate_getCollectionTracker();
}
tracker.add(fieldName, ((Collection) value).size());
}
}
Aggregations