屏蔽脏检查的属性 [英] Mask properties from dirty check

查看:84
本文介绍了屏蔽脏检查的属性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的所有表中都有一列,称为LoggedInPersonID.为了避免混乱的映射代码,Nhibernate拦截器会覆盖OnFlushDirty和OnSave来自动分配LoggedInPersonID属性.

I have a column in all my tables called LoggedInPersonID. To avoid cluttering mapping code, an Nhibernate Interceptor overrides OnFlushDirty and OnSave to assign the LoggedInPersonID property automatically.

如果LoggedInPersonID是唯一更改的属性,则我认为实体是干净的.此刻Nhibernate(理所当然)认为该实体是肮脏的.

If LoggedInPersonID is the only property changed, I consider the entity clean. At the moment Nhibernate (rightfully) considers the entity to be dirty.

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

Does any mapping construct exist to escape a property from Nhibernate's dirty check, while still including the column in any inserts/updates?

或者,我考虑过实现IPreUdateEventListener接口,并使用OnPreUpdate事件来检查OldState和State之间的唯一区别是否在属性LoggedInPersonID中,如果是,请取消更新.那是有效的方法吗?

Alternatively, I have considered implementing the IPreUdateEventListener interface and use the OnPreUpdate event to check whether the only difference between OldState and State is in the property LoggedInPersonID, and cancel the update if that is the case. Would that be a valid approach?

推荐答案

更简单的情况

如果实体不脏,我宁愿避免设置LoggedInPersonID.我不满意从IPreUdateEventListener取消更新:仍然发生许多其他处理,例如二级缓存更新和其他PostUpdate处理.

Simplier case

I would rather try to avoid setting LoggedInPersonID if the entity is not dirty. I am not comfortable with cancelling the update from IPreUdateEventListener: a lot of other processing still occurs, like second level cache updating, and other PostUpdate processing.

OnFlushDirty xml文档状态:

在刷新过程中检测到对象变脏时调用.

Called when an object is detected to be dirty, during a flush.

因此,这意味着NHibernate甚至在设置对象LoggedInPersonID之前就将其视为脏对象.

So this means NHibernate considers your object to be dirty even before you have set its LoggedInPersonID.

您可能应该在带有条件断点的拦截器中进行检查,以仅在遇到问题的实体类型上停止,并检查在currentStatepreviousState之间是否已经存在其他更改,然后您的代码才会影响其LoggedInPersonID.

You should probably check that in your interceptor with a conditional break-point to stop only on your entity type having troubles, and check if there is already some other changes between currentState and previousState before your code affects its LoggedInPersonID.

例如,也许您在其他地方已经设置了LoggedInPersonID的其他逻辑.

Maybe have you by example some other logic elsewhere which has already set LoggedInPersonID.

但是检查NHibernate代码,可能会有点混乱.在我看来,OnflushDirty可以在可能很脏的实体上调用. (也许这种可能会变脏"是由我在对上一个问题的回答中怀疑的东西引起的..)

But checking NHibernate code, it could be a bit muddier. It looks to me like OnflushDirty could be called on entities which might be dirty. (And maybe this "might be dirty" is caused by what I had suspected in my answer on your previous question.)

在这种情况下,您应该在拦截器内部进行脏检查.您可以在OnFlushDirty中执行脏检查,但是NHibernate仍然会自己进行脏检查,从而导致脏检查要进行两次.为了避免对每个实体进行两次脏检查,您需要先做一个主意:如果这是唯一的脏属性,请从脏检查中逐出LoggedInPersonID.

I such case, you should do your own dirty check inside your interceptor. You may do the dirty check in your OnFlushDirty, but then NHibernate will still do its own, causing the dirty check to be done twice. To avoid dirty checking twice each entity, you need then do your first idea: evicting LoggedInPersonID from the dirty check if this is the only dirty property.

NHibernate脏检查实现并非易事.比编写自己的脏支票更好地重用它.但这需要在拦截器中添加一些代码. (在此NHibernate.info博客的帮助下完成.)

NHibernate dirty check implementation is not trivial. Better reuse it than coding your own dirty check. But this need adding some code to your interceptor. (Done with the help of this blog on NHibernate.info.)

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;
    }
}

旁注:在您正在propertyNames[i].ToLower() == "loggedinpersonid"上进行测试的其他问题修订中,我看到了.如果需要,我通常更喜欢这样:StringComparer.OrdinalIgnoreCase.Equals(propertyNames[i], "LoggedInPersonID").这样可以避免在手动降低属性名称的大小写时搞砸了.

Side note : I have seen in your other question revisions your were testing on propertyNames[i].ToLower() == "loggedinpersonid". If you need that, I generally prefer do that this way : StringComparer.OrdinalIgnoreCase.Equals(propertyNames[i], "LoggedInPersonID"). This avoid messing up while manually lower-casing the property name.

也许用另一种方式我以后发现会更容易.

Maybe this other way I found later would be easier.

这篇关于屏蔽脏检查的属性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆