Nhibernate 从脏检查屏蔽属性

Nhibernate 从脏检查屏蔽属性,nhibernate,Nhibernate,在我所有的表中都有一列名为LoggedInPersonID。为了避免映射代码混乱,Nhibernate拦截器会重写OnFlushDirty和OnSave以自动分配LoggedInPersonID属性 如果LoggedInPersonID是唯一的属性,我认为实体是干净的。此时,Nhibernate(正确地)认为实体是脏的 是否存在从Nhibernate的脏检查中转义属性的映射构造,同时仍将列包含在任何插入/更新中 或者,我考虑实现IPreUdateEventListener接口,并使用OnPreU

在我所有的表中都有一列名为LoggedInPersonID。为了避免映射代码混乱,Nhibernate拦截器会重写OnFlushDirty和OnSave以自动分配LoggedInPersonID属性

如果LoggedInPersonID是唯一的属性,我认为实体是干净的。此时,Nhibernate(正确地)认为实体是脏的

是否存在从Nhibernate的脏检查中转义属性的映射构造,同时仍将列包含在任何插入/更新中

或者,我考虑实现IPreUdateEventListener接口,并使用OnPreUpdate事件检查OldState和State之间的唯一区别是否在属性LoggedPersonId中,如果是这样,则取消更新。这是一种有效的方法吗?

更简单的情况 如果实体不脏,我宁愿尝试避免设置
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;
    }
}