Nhibernate 检查会话是否脏,但不';t冲洗

Nhibernate 检查会话是否脏,但不';t冲洗,nhibernate,Nhibernate,我确信我已经看到了讨论的内容,但我一定没有使用正确的关键字,因为我现在找不到任何关于它的内容: 我有一个使用NHibernate持久性的桌面应用程序。我想使用会话的isDirty属性来通知用户是否有任何持久性数据已更改,并向用户显示关闭按钮或应用按钮和取消按钮,具体视情况而定 问题是调用isDirty会导致至少某些数据被刷新到数据库中,尽管我的刷新模式是从不。我很想知道为什么isDirty觉得必须刷新这些更改,但更重要的是,我想知道如何在不刷新的情况下获取这些信息 顺便说一句:因为我没有一个事务

我确信我已经看到了讨论的内容,但我一定没有使用正确的关键字,因为我现在找不到任何关于它的内容:

我有一个使用NHibernate持久性的桌面应用程序。我想使用会话的isDirty属性来通知用户是否有任何持久性数据已更改,并向用户显示关闭按钮或应用按钮和取消按钮,具体视情况而定

问题是调用isDirty会导致至少某些数据被刷新到数据库中,尽管我的刷新模式从不。我很想知道为什么isDirty觉得必须刷新这些更改,但更重要的是,我想知道如何在不刷新的情况下获取这些信息

顺便说一句:因为我没有一个事务在用户编辑表单上的信息的整个过程中进行包装,所以我假设任何刷新的更改都会保留下来,不管我最终是否提交了所有其他内容


那么,有人能告诉我如何在没有我不需要的功能的情况下获得我想要的功能吗?

我在viewmodel属性中进行了脏状态跟踪。在每个
PropertyChanged
上,我调用ViewModelBase类的
MarkAsDirty()
。这反映了一个属性,该属性随后绑定到“保存按钮”命令上


但是,如果你想使用NH跟踪,这可能符合你的要求。

我自己没有这样做,但在谷歌搜索之后,这似乎是可能的。在会话中循环所有加载的实体并检查它们是否脏,怎么样?您甚至可以手动比较加载的实体与当前实体状态

请尝试我在StackOverflow上找到的以下代码:()


您也可以尝试制作自己的。

我终于能够将注意力转移到这一点上,并制定出一个解决方案,如下所示:

    /// <summary>
    /// Check whether a session is "dirty" without triggering a flush
    /// </summary>
    /// <param name="session"></param>
    /// <returns>true if the session is "dirty", meaning that it will update the database when flushed</returns>
    /// <remarks>
    /// The rationale behind this is the need to determine if there's anything to flush to the database without actually
    /// running through the Flush process.  The problem with a premature Flush is that one may want to collect changes
    /// to persistent objects and only start a transaction later on to flush them.  I have this in a Winforms application
    /// and this method allows me to notify the user whether he has made changes that need saving while not leaving a
    /// transaction open while he works, which can cause locking issues.
    /// <para>
    /// Note that the check for dirty collections may give false positives, which is good enough for my purposes but 
    /// coule be improved upon using calls to GetOrphans and other persistent-collection methods.</para>
    /// </remarks>
    public static bool IsDirtyNoFlush(this ISession session)
    {
        var pc = session.GetSessionImplementation().PersistenceContext;
        if (pc.EntitiesByKey.Values.Any(o => IsDirtyEntity(session, o)))
            return true;

        return pc.CollectionEntries.Keys.Cast<IPersistentCollection>()
            .Any(coll => coll.WasInitialized && coll.IsDirty);
    }
//
///在不触发刷新的情况下检查会话是否“脏”
/// 
/// 
///如果会话为“脏”,则为true,这意味着它将在刷新时更新数据库
/// 
///这背后的基本原理是需要确定是否有任何内容需要在没有实际操作的情况下刷新到数据库中
///正在运行刷新过程。过早刷新的问题是可能需要收集更改
///创建持久对象,并仅在以后启动事务以刷新它们。我在Winforms应用程序中有这个
///这个方法允许我通知用户是否做了需要保存的更改,同时不留下
///事务在他工作时打开,这可能会导致锁定问题。
/// 
///请注意,对脏集合的检查可能会给出误报,这对于我来说已经足够好了,但是
///在使用对Get孤儿和其他持久性收集方法的调用后,可能会有所改进。
/// 
公共静态bool IsDirtyNoFlush(此ISession会话)
{
var pc=session.GetSessionImplementation().PersistenceContext;
if(pc.EntitiesByKey.Values.Any(o=>IsDirtyEntity(session,o)))
返回true;
返回pc.CollectionEntries.Keys.Cast()
.Any(coll=>coll.WasInitialized&&coll.IsDirty);
}

第一部分基本上与上面Shahin推荐的一样。最后一行是我错过的。正如我在评论中提到的,它仍然不如内置的IsDirty()好,因为人们会认识到,例如,从持久性集合中删除一个项,然后将其放回,使其不再脏,而我的方法将给出一个假阳性。尽管如此,它对于我的目的(以及我想象中的大多数其他目的)来说已经完全足够了,并且避免了刷新。

谢谢,但我认为跟踪所有更改(包括对包含的集合的添加、删除和更新)将是太多的工作。特别是因为如果用户将值更改回原来的值,我想重置脏标志。NH必须追踪所有这些。至于SessionExtension,这些方法很好(虽然有一点缺陷),我使用它们,但是我必须编写一系列代码来获取一个对象并检查它的所有属性,递归地检查它包含的集合的所有属性。谢谢。我知道这些方法,甚至编写了包装器,可以按照您的建议执行,但它们不处理级联更改的问题。例如,如果我删除了一个持久性集合的成员,就我所知,该信息无法通过这种方式确定。它只在冲洗过程中出现。我认为有一种方法可以将整个级联过程作为一种“干运行”来确定是否有这样的变化,但我不知道怎么做。
Type t = Type.GetType(entityEntry.EntityName);
if (t == typeof(Employee))
{
    //do something
}
    /// <summary>
    /// Check whether a session is "dirty" without triggering a flush
    /// </summary>
    /// <param name="session"></param>
    /// <returns>true if the session is "dirty", meaning that it will update the database when flushed</returns>
    /// <remarks>
    /// The rationale behind this is the need to determine if there's anything to flush to the database without actually
    /// running through the Flush process.  The problem with a premature Flush is that one may want to collect changes
    /// to persistent objects and only start a transaction later on to flush them.  I have this in a Winforms application
    /// and this method allows me to notify the user whether he has made changes that need saving while not leaving a
    /// transaction open while he works, which can cause locking issues.
    /// <para>
    /// Note that the check for dirty collections may give false positives, which is good enough for my purposes but 
    /// coule be improved upon using calls to GetOrphans and other persistent-collection methods.</para>
    /// </remarks>
    public static bool IsDirtyNoFlush(this ISession session)
    {
        var pc = session.GetSessionImplementation().PersistenceContext;
        if (pc.EntitiesByKey.Values.Any(o => IsDirtyEntity(session, o)))
            return true;

        return pc.CollectionEntries.Keys.Cast<IPersistentCollection>()
            .Any(coll => coll.WasInitialized && coll.IsDirty);
    }