use of org.hibernate.engine.spi.EntityEntry in project hibernate-orm by hibernate.
the class DefaultFlushEntityEventListener method scheduleUpdate.
private boolean scheduleUpdate(final FlushEntityEvent event) {
final EntityEntry entry = event.getEntityEntry();
final EventSource session = event.getSession();
final Object entity = event.getEntity();
final Status status = entry.getStatus();
final EntityPersister persister = entry.getPersister();
final Object[] values = event.getPropertyValues();
if (LOG.isTraceEnabled()) {
if (status == Status.DELETED) {
if (!persister.isMutable()) {
LOG.tracev("Updating immutable, deleted entity: {0}", MessageHelper.infoString(persister, entry.getId(), session.getFactory()));
} else if (!entry.isModifiableEntity()) {
LOG.tracev("Updating non-modifiable, deleted entity: {0}", MessageHelper.infoString(persister, entry.getId(), session.getFactory()));
} else {
LOG.tracev("Updating deleted entity: ", MessageHelper.infoString(persister, entry.getId(), session.getFactory()));
}
} else {
LOG.tracev("Updating entity: {0}", MessageHelper.infoString(persister, entry.getId(), session.getFactory()));
}
}
final boolean intercepted = !entry.isBeingReplicated() && handleInterception(event);
// increment the version number (if necessary)
final Object nextVersion = getNextVersion(event);
// if it was dirtied by a collection only
int[] dirtyProperties = event.getDirtyProperties();
if (event.isDirtyCheckPossible() && dirtyProperties == null) {
if (!intercepted && !event.hasDirtyCollection()) {
throw new AssertionFailure("dirty, but no dirty properties");
}
dirtyProperties = ArrayHelper.EMPTY_INT_ARRAY;
}
// check nullability but do not doAfterTransactionCompletion command execute
// we'll use scheduled updates for that.
new Nullability(session).checkNullability(values, persister, true);
// schedule the update
// note that we intentionally do _not_ pass in currentPersistentState!
session.getActionQueue().addAction(new EntityUpdateAction(entry.getId(), values, dirtyProperties, event.hasDirtyCollection(), (status == Status.DELETED && !entry.isModifiableEntity() ? persister.getPropertyValues(entity) : entry.getLoadedState()), entry.getVersion(), nextVersion, entity, entry.getRowId(), persister, session));
return intercepted;
}
use of org.hibernate.engine.spi.EntityEntry in project hibernate-orm by hibernate.
the class DefaultFlushEntityEventListener method getNextVersion.
/**
* Convenience method to retrieve an entities next version value
*/
private Object getNextVersion(FlushEntityEvent event) throws HibernateException {
EntityEntry entry = event.getEntityEntry();
EntityPersister persister = entry.getPersister();
if (persister.isVersioned()) {
Object[] values = event.getPropertyValues();
if (entry.isBeingReplicated()) {
return Versioning.getVersion(values, persister);
} else {
int[] dirtyProperties = event.getDirtyProperties();
final boolean isVersionIncrementRequired = isVersionIncrementRequired(event, entry, persister, dirtyProperties);
final Object nextVersion = isVersionIncrementRequired ? Versioning.increment(entry.getVersion(), persister.getVersionType(), event.getSession()) : //use the current version
entry.getVersion();
Versioning.setVersion(values, nextVersion, persister);
return nextVersion;
}
} else {
return null;
}
}
use of org.hibernate.engine.spi.EntityEntry in project hibernate-orm by hibernate.
the class DefaultFlushEntityEventListener method onFlushEntity.
/**
* Flushes a single entity's state to the database, by scheduling
* an update action, if necessary
*/
public void onFlushEntity(FlushEntityEvent event) throws HibernateException {
final Object entity = event.getEntity();
final EntityEntry entry = event.getEntityEntry();
final EventSource session = event.getSession();
final EntityPersister persister = entry.getPersister();
final Status status = entry.getStatus();
final Type[] types = persister.getPropertyTypes();
final boolean mightBeDirty = entry.requiresDirtyCheck(entity);
final Object[] values = getValues(entity, entry, mightBeDirty, session);
event.setPropertyValues(values);
//TODO: avoid this for non-new instances where mightBeDirty==false
boolean substitute = wrapCollections(session, persister, types, values);
if (isUpdateNecessary(event, mightBeDirty)) {
substitute = scheduleUpdate(event) || substitute;
}
if (status != Status.DELETED) {
// now update the object .. has to be outside the main if block above (because of collections)
if (substitute) {
persister.setPropertyValues(entity, values);
}
// We don't want to touch collections reachable from a deleted object
if (persister.hasCollections()) {
new FlushVisitor(session, entity).processEntityPropertyValues(values, types);
}
}
}
use of org.hibernate.engine.spi.EntityEntry 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()) {
dirtyProperties = persister.resolveAttributeIndexes(((SelfDirtinessTracker) entity).$$_hibernate_getDirtyAttributes());
} else {
dirtyProperties = new int[0];
}
} else {
// see if the custom dirtiness strategy can tell us...
class DirtyCheckContextImpl implements CustomEntityDirtinessStrategy.DirtyCheckContext {
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) 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.EntityEntry in project hibernate-orm by hibernate.
the class DefaultMergeEventListener method existsInDatabase.
private boolean existsInDatabase(Object entity, EventSource source, EntityPersister persister) {
EntityEntry entry = source.getPersistenceContext().getEntry(entity);
if (entry == null) {
Serializable id = persister.getIdentifier(entity, source);
if (id != null) {
final EntityKey key = source.generateEntityKey(id, persister);
final Object managedEntity = source.getPersistenceContext().getEntity(key);
entry = source.getPersistenceContext().getEntry(managedEntity);
}
}
return entry != null && entry.isExistsInDatabase();
}
Aggregations