📄 defaultflushentityeventlistener.cs
字号:
throw new AssertionFailure("dirty, but no dirty properties");
}
dirtyProperties = ArrayHelper.EmptyIntArray;
}
// check nullability but do not perform 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.ActionQueue.AddAction(
new EntityUpdateAction(entry.Id, values, dirtyProperties,
@event.HasDirtyCollection, entry.LoadedState, entry.Version,
nextVersion, entity, persister, session));
return intercepted;
}
protected virtual void Validate(object entity, IEntityPersister persister, Status status, EntityMode entityMode)
{
// validate() instances of Validatable
if (status == Status.Loaded && persister.ImplementsValidatable(entityMode))
{
((IValidatable)entity).Validate();
}
}
protected virtual bool HandleInterception(FlushEntityEvent @event)
{
ISessionImplementor session = @event.Session;
EntityEntry entry = @event.EntityEntry;
IEntityPersister persister = entry.Persister;
object entity = @event.Entity;
//give the Interceptor a chance to modify property values
object[] values = @event.PropertyValues;
bool intercepted = InvokeInterceptor(session, entity, entry, values, persister);
//now we might need to recalculate the dirtyProperties array
if (intercepted && @event.DirtyCheckPossible && !@event.DirtyCheckHandledByInterceptor)
{
int[] dirtyProperties;
if (@event.HasDatabaseSnapshot)
{
dirtyProperties = persister.FindModified(@event.DatabaseSnapshot, values, entity, session);
}
else
{
dirtyProperties = persister.FindDirty(values, entry.LoadedState, entity, session);
}
@event.DirtyProperties = dirtyProperties;
}
return intercepted;
}
protected virtual bool InvokeInterceptor(ISessionImplementor session, object entity, EntityEntry entry, object[] values, IEntityPersister persister)
{
return session.Interceptor.OnFlushDirty(entity, entry.Id, values, entry.LoadedState, persister.PropertyNames, persister.PropertyTypes);
}
private object GetNextVersion(FlushEntityEvent @event)
{
// Convience method to retreive an entities next version value
EntityEntry entry = @event.EntityEntry;
IEntityPersister persister = entry.Persister;
if (persister.IsVersioned)
{
object[] values = @event.PropertyValues;
if (entry.IsBeingReplicated)
{
return Versioning.GetVersion(values, persister);
}
else
{
int[] dirtyProperties = @event.DirtyProperties;
bool isVersionIncrementRequired = IsVersionIncrementRequired(@event, entry, persister, dirtyProperties);
object nextVersion = isVersionIncrementRequired ?
Versioning.Increment(entry.Version, persister.VersionType, @event.Session) :
entry.Version; //use the current version
Versioning.SetVersion(values, nextVersion, persister);
return nextVersion;
}
}
else
{
return null;
}
}
private bool IsVersionIncrementRequired(FlushEntityEvent @event, EntityEntry entry, IEntityPersister persister, int[] dirtyProperties)
{
bool isVersionIncrementRequired =
entry.Status != Status.Deleted &&
(dirtyProperties == null ||
Versioning.IsVersionIncrementRequired(dirtyProperties, @event.HasDirtyCollection, persister.PropertyVersionability));
return isVersionIncrementRequired;
}
/// <summary>
/// Performs all necessary checking to determine if an entity needs an SQL update
/// to synchronize its state to the database. Modifies the event by side-effect!
/// Note: this method is quite slow, avoid calling if possible!
/// </summary>
protected bool IsUpdateNecessary(FlushEntityEvent @event)
{
IEntityPersister persister = @event.EntityEntry.Persister;
Status status = @event.EntityEntry.Status;
if (!@event.DirtyCheckPossible)
{
return true;
}
else
{
int[] dirtyProperties = @event.DirtyProperties;
if (dirtyProperties != null && dirtyProperties.Length != 0)
{
return true; //TODO: suck into event class
}
else
{
return HasDirtyCollections(@event, persister, status);
}
}
}
private bool HasDirtyCollections(FlushEntityEvent @event, IEntityPersister persister, Status status)
{
if (IsCollectionDirtyCheckNecessary(persister, status))
{
DirtyCollectionSearchVisitor visitor = new DirtyCollectionSearchVisitor(@event.Session, persister.PropertyVersionability);
visitor.ProcessEntityPropertyValues(@event.PropertyValues, persister.PropertyTypes);
bool hasDirtyCollections = visitor.WasDirtyCollectionFound;
@event.HasDirtyCollection = hasDirtyCollections;
return hasDirtyCollections;
}
else
{
return false;
}
}
private bool IsCollectionDirtyCheckNecessary(IEntityPersister persister, Status status)
{
return status == Status.Loaded && persister.IsVersioned && persister.HasCollections;
}
/// <summary> Perform a dirty check, and attach the results to the event</summary>
protected virtual void DirtyCheck(FlushEntityEvent @event)
{
object entity = @event.Entity;
object[] values = @event.PropertyValues;
ISessionImplementor session = @event.Session;
EntityEntry entry = @event.EntityEntry;
IEntityPersister persister = entry.Persister;
object id = entry.Id;
object[] loadedState = entry.LoadedState;
int[] dirtyProperties = session.Interceptor.FindDirty(entity, id, values, loadedState, persister.PropertyNames, persister.PropertyTypes);
@event.DatabaseSnapshot = null;
bool interceptorHandledDirtyCheck;
bool 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
{
// dirty check against the database snapshot, if possible/necessary
object[] databaseSnapshot = GetDatabaseSnapshot(session, persister, id);
if (databaseSnapshot != null)
{
dirtyProperties = persister.FindModified(databaseSnapshot, values, entity, session);
cannotDirtyCheck = false;
@event.DatabaseSnapshot = databaseSnapshot;
}
}
}
else
{
// the Interceptor handled the dirty checking
cannotDirtyCheck = false;
interceptorHandledDirtyCheck = true;
}
@event.DirtyProperties = dirtyProperties;
@event.DirtyCheckHandledByInterceptor = interceptorHandledDirtyCheck;
@event.DirtyCheckPossible = !cannotDirtyCheck;
}
private object[] GetDatabaseSnapshot(ISessionImplementor session, IEntityPersister persister, object id)
{
if (persister.IsSelectBeforeUpdateRequired)
{
object[] snapshot = session.PersistenceContext.GetDatabaseSnapshot(id, persister);
if (snapshot == null)
{
//do we even really need this? the update will fail anyway....
if (session.Factory.Statistics.IsStatisticsEnabled)
{
session.Factory.StatisticsImplementor.OptimisticFailure(persister.EntityName);
}
throw new StaleObjectStateException(persister.EntityName, id);
}
else
{
return snapshot;
}
}
else
{
//TODO: optimize away this lookup for entities w/o unsaved-value="undefined"
EntityKey entityKey = new EntityKey(id, persister, session.EntityMode);
return session.PersistenceContext.GetCachedDatabaseSnapshot(entityKey);
}
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -