📄 abstractsaveeventlistener.cs
字号:
source.PersistenceContext.AddEntry(entity, Status.Saving, null, id, null, LockMode.Write, useIdentityColumn, persister, false, false);
CascadeBeforeSave(source, persister, entity, anything);
// NH-962: This was originally done before many-to-one cascades.
if (useIdentityColumn && !shouldDelayIdentityInserts)
{
log.Debug("executing insertions");
source.ActionQueue.ExecuteInserts();
}
object[] values = persister.GetPropertyValuesToInsert(entity, GetMergeMap(anything), source);
IType[] types = persister.PropertyTypes;
bool substitute = SubstituteValuesIfNecessary(entity, id, values, persister, source);
if (persister.HasCollections)
{
substitute = substitute || VisitCollectionsBeforeSave(entity, id, values, types, source);
}
if (substitute)
{
persister.SetPropertyValues(entity, values, source.EntityMode);
}
TypeFactory.DeepCopy(values, types, persister.PropertyUpdateability, values, source);
new ForeignKeys.Nullifier(entity, false, useIdentityColumn, source).NullifyTransientReferences(values, types);
new Nullability(source).CheckNullability(values, persister, false);
if (useIdentityColumn)
{
EntityIdentityInsertAction insert = new EntityIdentityInsertAction(values, entity, persister, source, shouldDelayIdentityInserts);
if (!shouldDelayIdentityInserts)
{
log.Debug("executing identity-insert immediately");
source.ActionQueue.Execute(insert);
id = insert.GeneratedId;
//now done in EntityIdentityInsertAction
//persister.setIdentifier( entity, id, source.getEntityMode() );
key = new EntityKey(id, persister, source.EntityMode);
source.PersistenceContext.CheckUniqueness(key, entity);
//source.getBatcher().executeBatch(); //found another way to ensure that all batched joined inserts have been executed
}
else
{
log.Debug("delaying identity-insert due to no transaction in progress");
source.ActionQueue.AddAction(insert);
key = insert.DelayedEntityKey;
}
}
object version = Versioning.GetVersion(values, persister);
source.PersistenceContext.AddEntity(entity, Status.Loaded, values, key, version, LockMode.Write, useIdentityColumn, persister, VersionIncrementDisabled, false);
//source.getPersistenceContext().removeNonExist( new EntityKey( id, persister, source.getEntityMode() ) );
if (!useIdentityColumn)
{
source.ActionQueue.AddAction(new EntityInsertAction(id, values, entity, version, persister, source));
}
CascadeAfterSave(source, persister, entity, anything);
MarkInterceptorDirty(entity, persister, source);
return id;
}
private void MarkInterceptorDirty(object entity, IEntityPersister persister, IEventSource source)
{
if (FieldInterceptionHelper.IsInstrumented(entity))
{
IFieldInterceptor interceptor = FieldInterceptionHelper.InjectFieldInterceptor(entity, persister.EntityName, null, source);
interceptor.MarkDirty();
}
}
protected virtual IDictionary GetMergeMap(object anything)
{
return null;
}
protected virtual bool VisitCollectionsBeforeSave(object entity, object id, object[] values, IType[] types, IEventSource source)
{
WrapVisitor visitor = new WrapVisitor(source);
// substitutes into values by side-effect
visitor.ProcessEntityPropertyValues(values, types);
return visitor.SubstitutionRequired;
}
/// <summary>
/// Perform any property value substitution that is necessary
/// (interceptor callback, version initialization...)
/// </summary>
/// <param name="entity">The entity </param>
/// <param name="id">The entity identifier </param>
/// <param name="values">The snapshot entity state </param>
/// <param name="persister">The entity persister </param>
/// <param name="source">The originating session </param>
/// <returns>
/// True if the snapshot state changed such that
/// reinjection of the values into the entity is required.
/// </returns>
protected virtual bool SubstituteValuesIfNecessary(object entity, object id, object[] values, IEntityPersister persister, ISessionImplementor source)
{
bool substitute = source.Interceptor.OnSave(entity, id, values, persister.PropertyNames, persister.PropertyTypes);
//keep the existing version number in the case of replicate!
if (persister.IsVersioned)
{
// NH Specific feature (H3.2 use null value for versionProperty; NH ask to persister to know if a valueType mean unversioned)
object versionValue = values[persister.VersionProperty];
substitute |= Versioning.SeedVersion(values, persister.VersionProperty, persister.VersionType, persister.IsUnsavedVersion(versionValue), source);
}
return substitute;
}
/// <summary> Handles the calls needed to perform pre-save cascades for the given entity. </summary>
/// <param name="source">The session from which the save event originated.</param>
/// <param name="persister">The entity's persister instance. </param>
/// <param name="entity">The entity to be saved. </param>
/// <param name="anything">Generally cascade-specific data </param>
protected virtual void CascadeBeforeSave(IEventSource source, IEntityPersister persister, object entity, object anything)
{
// cascade-save to many-to-one BEFORE the parent is saved
source.PersistenceContext.IncrementCascadeLevel();
try
{
new Cascade(CascadeAction, CascadePoint.BeforeInsertAfterDelete, source).CascadeOn(persister, entity, anything);
}
finally
{
source.PersistenceContext.DecrementCascadeLevel();
}
}
/// <summary> Handles to calls needed to perform post-save cascades. </summary>
/// <param name="source">The session from which the event originated. </param>
/// <param name="persister">The entity's persister instance. </param>
/// <param name="entity">The entity being saved. </param>
/// <param name="anything">Generally cascade-specific data </param>
protected virtual void CascadeAfterSave(IEventSource source, IEntityPersister persister, object entity, object anything)
{
// cascade-save to collections AFTER the collection owner was saved
source.PersistenceContext.IncrementCascadeLevel();
try
{
new Cascade(CascadeAction, CascadePoint.AfterInsertBeforeDelete, source).CascadeOn(persister, entity, anything);
}
finally
{
source.PersistenceContext.DecrementCascadeLevel();
}
}
/// <summary>
/// Determine whether the entity is persistent, detached, or transient
/// </summary>
/// <param name="entity">The entity to check </param>
/// <param name="entityName">The name of the entity </param>
/// <param name="entry">The entity's entry in the persistence context </param>
/// <param name="source">The originating session. </param>
/// <returns> The state. </returns>
protected virtual EntityState GetEntityState(object entity, string entityName, EntityEntry entry, ISessionImplementor source)
{
if (entry != null)
{
// the object is persistent
//the entity is associated with the session, so check its status
if (entry.Status != Status.Deleted)
{
// do nothing for persistent instances
if (log.IsDebugEnabled)
{
log.Debug("persistent instance of: " + GetLoggableName(entityName, entity));
}
return EntityState.Persistent;
}
else
{
//ie. e.status==DELETED
if (log.IsDebugEnabled)
{
log.Debug("deleted instance of: " + GetLoggableName(entityName, entity));
}
return EntityState.Deleted;
}
}
else
{
//the object is transient or detached
//the entity is not associated with the session, so
//try interceptor and unsaved-value
if (ForeignKeys.IsTransient(entityName, entity, AssumedUnsaved, source))
{
if (log.IsDebugEnabled)
{
log.Debug("transient instance of: " + GetLoggableName(entityName, entity));
}
return EntityState.Transient;
}
else
{
if (log.IsDebugEnabled)
{
log.Debug("detached instance of: " + GetLoggableName(entityName, entity));
}
return EntityState.Detached;
}
}
}
protected virtual string GetLoggableName(string entityName, object entity)
{
return entityName ?? entity.GetType().FullName;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -