📄 abstractsaveeventlistener.cs
字号:
using System;
using System.Collections;
using log4net;
using NHibernate.Action;
using NHibernate.Classic;
using NHibernate.Engine;
using NHibernate.Id;
using NHibernate.Impl;
using NHibernate.Intercept;
using NHibernate.Persister.Entity;
using NHibernate.Type;
using Status=NHibernate.Engine.Status;
namespace NHibernate.Event.Default
{
public enum EntityState
{
Undefined = -1,
Persistent = 0,
Transient = 1,
Detached = 2,
Deleted = 3
}
/// <summary>
/// A convenience bas class for listeners responding to save events.
/// </summary>
[Serializable]
public abstract class AbstractSaveEventListener : AbstractReassociateEventListener
{
private static readonly ILog log = LogManager.GetLogger(typeof(AbstractSaveEventListener));
protected virtual bool? AssumedUnsaved
{
get { return null; }
}
protected abstract CascadingAction CascadeAction { get;}
/// <summary>
/// After the save, will te version number be incremented
/// if the instance is modified?
/// </summary>
/// <returns> True if the version will be incremented on an entity change after save; false otherwise. </returns>
protected virtual bool VersionIncrementDisabled
{
get { return false; }
}
protected virtual bool InvokeSaveLifecycle(object entity, IEntityPersister persister, IEventSource source)
{
// Sub-insertions should occur before containing insertion so
// Try to do the callback now
if (persister.ImplementsLifecycle(source.EntityMode))
{
log.Debug("calling OnSave()");
if (((ILifecycle)entity).OnSave(source) == LifecycleVeto.Veto)
{
log.Debug("insertion vetoed by OnSave()");
return true;
}
}
return false;
}
protected virtual void Validate(object entity, IEntityPersister persister, IEventSource source)
{
if (persister.ImplementsValidatable(source.EntityMode))
{
((IValidatable)entity).Validate();
}
}
/// <summary>
/// Prepares the save call using the given requested id.
/// </summary>
/// <param name="entity">The entity to be saved. </param>
/// <param name="requestedId">The id to which to associate the entity. </param>
/// <param name="entityName">The name of the entity being saved. </param>
/// <param name="anything">Generally cascade-specific information. </param>
/// <param name="source">The session which is the source of this save event. </param>
/// <returns> The id used to save the entity. </returns>
protected virtual object SaveWithRequestedId(object entity, object requestedId, string entityName, object anything, IEventSource source)
{
return PerformSave(entity, requestedId, source.GetEntityPersister(entity), false, anything, source, true);
}
/// <summary>
/// Prepares the save call using a newly generated id.
/// </summary>
/// <param name="entity">The entity to be saved </param>
/// <param name="entityName">The entity-name for the entity to be saved </param>
/// <param name="anything">Generally cascade-specific information. </param>
/// <param name="source">The session which is the source of this save event. </param>
/// <param name="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).
/// </param>
/// <returns>
/// The id used to save the entity; may be null depending on the
/// type of id generator used and the requiresImmediateIdAccess value
/// </returns>
protected virtual object SaveWithGeneratedId(object entity, string entityName, object anything, IEventSource source, bool requiresImmediateIdAccess)
{
IEntityPersister persister = source.GetEntityPersister(entity);
object generatedId = persister.IdentifierGenerator.Generate(source, entity);
if (generatedId == null)
{
throw new IdentifierGenerationException("null id generated for:" + entity.GetType());
}
else if (generatedId == IdentifierGeneratorFactory.ShortCircuitIndicator)
{
return source.GetIdentifier(entity);
}
else if (generatedId == IdentifierGeneratorFactory.PostInsertIndicator)
{
return PerformSave(entity, null, persister, true, anything, source, requiresImmediateIdAccess);
}
else
{
if (log.IsDebugEnabled)
{
log.Debug(string.Format("generated identifier: {0}, using strategy: {1}",
persister.IdentifierType.ToLoggableString(generatedId, source.Factory),
persister.IdentifierGenerator.GetType().FullName));
}
return PerformSave(entity, generatedId, persister, false, anything, source, true);
}
}
/// <summary>
/// Prepares the save call by checking the session caches for a pre-existing
/// entity and performing any lifecycle callbacks.
/// </summary>
/// <param name="entity">The entity to be saved. </param>
/// <param name="id">The id by which to save the entity. </param>
/// <param name="persister">The entity's persister instance. </param>
/// <param name="useIdentityColumn">Is an identity column being used? </param>
/// <param name="anything">Generally cascade-specific information. </param>
/// <param name="source">The session from which the event originated. </param>
/// <param name="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).
/// </param>
/// <returns>
/// The id used to save the entity; may be null depending on the
/// type of id generator used and the requiresImmediateIdAccess value
/// </returns>
protected virtual object PerformSave(object entity, object id, IEntityPersister persister, bool useIdentityColumn, object anything, IEventSource source, bool requiresImmediateIdAccess)
{
if (log.IsDebugEnabled)
{
log.Debug("saving " + MessageHelper.InfoString(persister, id, source.Factory));
}
EntityKey key;
if (!useIdentityColumn)
{
key = new EntityKey(id, persister, source.EntityMode);
object old = source.PersistenceContext.GetEntity(key);
if (old != null)
{
if (source.PersistenceContext.GetEntry(old).Status == Status.Deleted)
{
source.ForceFlush(source.PersistenceContext.GetEntry(old));
}
else
{
throw new NonUniqueObjectException(id, persister.EntityName);
}
}
persister.SetIdentifier(entity, id, source.EntityMode);
}
else
{
key = null;
}
if (InvokeSaveLifecycle(entity, persister, source))
{
return id; //EARLY EXIT
}
return PerformSaveOrReplicate(entity, key, persister, useIdentityColumn, anything, source, requiresImmediateIdAccess);
}
/// <summary>
/// Performs all the actual work needed to save an entity (well to get the save moved to
/// the execution queue).
/// </summary>
/// <param name="entity">The entity to be saved </param>
/// <param name="key">The id to be used for saving the entity (or null, in the case of identity columns) </param>
/// <param name="persister">The entity's persister instance. </param>
/// <param name="useIdentityColumn">Should an identity column be used for id generation? </param>
/// <param name="anything">Generally cascade-specific information. </param>
/// <param name="source">The session which is the source of the current event. </param>
/// <param name="requiresImmediateIdAccess">
/// Is access to the identifier required immediately
/// after the completion of the save? persist(), for example, does not require this...
/// </param>
/// <returns>
/// The id used to save the entity; may be null depending on the
/// type of id generator used and the requiresImmediateIdAccess value
/// </returns>
protected virtual object PerformSaveOrReplicate(object entity, EntityKey key, IEntityPersister persister, bool useIdentityColumn, object anything, IEventSource source, bool requiresImmediateIdAccess)
{
Validate(entity, persister, source);
object id = key == null ? null : key.Identifier;
// NH Different behavior (shouldDelayIdentityInserts=false anyway)
//bool inTxn = source.ConnectionManager.IsInActiveTransaction;
//bool shouldDelayIdentityInserts = !inTxn && !requiresImmediateIdAccess;
bool shouldDelayIdentityInserts = false;
// Put a placeholder in entries, so we don't recurse back and try to save() the
// same object again. QUESTION: should this be done before onSave() is called?
// likewise, should it be done before onUpdate()?
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -