Nhibernate 从脏检查屏蔽属性
在我所有的表中都有一列名为LoggedInPersonID。为了避免映射代码混乱,Nhibernate拦截器会重写OnFlushDirty和OnSave以自动分配LoggedInPersonID属性 如果LoggedInPersonID是唯一的属性,我认为实体是干净的。此时,Nhibernate(正确地)认为实体是脏的 是否存在从Nhibernate的脏检查中转义属性的映射构造,同时仍将列包含在任何插入/更新中 或者,我考虑实现IPreUdateEventListener接口,并使用OnPreUpdate事件检查OldState和State之间的唯一区别是否在属性LoggedPersonId中,如果是这样,则取消更新。这是一种有效的方法吗?更简单的情况 如果实体不脏,我宁愿尝试避免设置Nhibernate 从脏检查屏蔽属性,nhibernate,Nhibernate,在我所有的表中都有一列名为LoggedInPersonID。为了避免映射代码混乱,Nhibernate拦截器会重写OnFlushDirty和OnSave以自动分配LoggedInPersonID属性 如果LoggedInPersonID是唯一的属性,我认为实体是干净的。此时,Nhibernate(正确地)认为实体是脏的 是否存在从Nhibernate的脏检查中转义属性的映射构造,同时仍将列包含在任何插入/更新中 或者,我考虑实现IPreUdateEventListener接口,并使用OnPreU
LoggedInPersonID
。我对从IPreUdateEventListener
取消更新感到不舒服:仍然会发生许多其他处理,如二级缓存更新和其他postate更新处理
OnFlushDirty
xml文档状态:
在冲洗过程中检测到对象变脏时调用
因此,这意味着在设置对象的LoggedInPersonID
之前,NHibernate就认为对象是脏的
您可能应该在您的拦截器中使用条件断点来检查这一点,以便仅在您的实体类型出现问题时停止,并在代码影响其LoggedPersonId
之前检查currentState
和previousState
之间是否已经存在一些其他更改
举例来说,您可能在其他地方已经设置了LoggedInPersonID
的其他逻辑
较难的情况
但是检查NHibernate代码,可能会有点混乱。在我看来,OnflushDirty
可以在可能脏的实体上调用。(也许这“可能很脏”是由以下原因造成的。)
在这种情况下,你应该在你的拦截器内做你自己的肮脏检查。您可以在您的OnFlushDirty
中执行脏检查,但NHibernate仍将执行自己的脏检查,导致脏检查执行两次。为了避免对每个实体进行两次脏检查,您需要执行第一个想法:如果这是唯一的脏属性,则从脏检查中逐出LoggedInPersonID
NHibernate脏检查的实现并非微不足道。与其编写自己的脏支票,不如重用它。但这需要向拦截器添加一些代码。(在的帮助下完成。)
旁注:我看到您在测试属性名称[I].ToLower()=“loggedinpersonid”
。如果需要,我通常更喜欢这样做:StringComparer.OrdinalIgnoreCase.Equals(propertyNames[I],“LoggedInPersonID”)
。这样可以避免在手动降低属性名称的大小写时出现混乱
其他解决方案
也许我以后发现会更容易。我认为如果您已经在OnSave中更改了属性,脏检查将在之后进行,最后在已经决定的情况下,将发生OnFlushDirty。至少如果(不必要地)对对象调用Save()或SaveOrUpdate(),尽管它不是新创建的对象
using NHibernate;
using NHibernate.Type;
using NHibernate.Proxy;
...
public class LoggedInPersonIDInterceptor : EmptyInterceptor
{
...
// your previous code handling the setting of LoggedInPersonID
...
private ISession _session;
public override void SetSession(ISession session)
{
_session = session;
}
public override int[] FindDirty(object entity, object id,
object[] currentState, object[] previousState,
string[] propertyNames, IType[] types)
{
var sessionImpl = _session.GetSessionImplementation();
var persistenceContext = sessionImpl.PersistenceContext;
var entry = persistenceContext.GetEntry(entity);
if (entry == null)
{
// The blog post try to handle proxy case but that part looks
// buggy to me. If you do not need to handle proxies, just let
// default implementation do the job by returning null here.
return null;
}
var persister = sessionImpl.Factory.GetEntityPersister(entry.EntityName);
var dirtyPropertiesIndexes = persister.FindDirty(currentState,
previousState, entity, sessionImpl);
// Probable superfluous null check...
if (dirtyPropertiesIndexes == null || dirtyPropertiesIndexes.Length != 1)
{
return dirtyPropertiesIndexes;
}
if (propertyNames[dirtyPropertiesIndexes[0]] == "LoggedInPersonID")
{
// return empty array for telling that nothing has changed
return new int[] {};
}
return dirtyPropertiesIndexes;
}
}