NHibernate的儿童会议不正常冲洗

我们通过NHibernate事件监听器实现了一个审计系统。 在我们的听众中,我们跟踪所有的变化并将它们写出到我们的审计表中。 为了尽量提高性能,我们将Guid用于审计表,以便我们尽可能地批量更新。

我们正在写出更新到“孩子会议”,我们得到这样的结果:

 protected ISession GetSession(AbstractEvent @event)
 {
     if (@event == null)
     {
        throw new ArgumentNullException("event");
     }

        ISession childSession = @event.Session.GetSession(EntityMode.Poco);

        return childSession;
 } 

从NHibernate文档中,这个会话应该是一个“子”会话,它继承了它的父节点的所有属性 - 包括事务。

一旦我们创建了实体,我们将它保存到会话中:

childSession.Save(auditLogEntry);

所有这些都是在一个事务中调用的,我希望一旦事务被提交,对childSession所做的更改就会刷新。 不幸的是,没有任何事情发生,并且变化不会冲淡。

应该指出的是,我可以在保存后立即使用手动刷新,但这对我们不起作用,因为这些更改将不再进行批处理(这会产生不可接受的性能)。

起初我认为这种行为仅限于事件,但我能够将其抽象为单元测试以复制行为。

  public void When_Saving_Audit_Log_Records_To_Child_Session_Flushes_When_Transaction_Committed()
    {
        ISession session = GetSession();
        session.FlushMode = FlushMode.Commit;

        ITransaction transaction = session.BeginTransaction();

        ISession childSession = session.GetSession(EntityMode.Poco);

        AuditLogEntry entry = CreateAuditLogEntry();
        entry.AddAuditLogEntryDetail(CreateAuditLogEntryDetail());
        entry.AddAuditLogEntryDetail(CreateAuditLogEntryDetail());

        childSession.Save(entry);
        transaction.Commit();
    }

protected ISession GetSession()
    {
        return _sessionFactory.OpenSession();
    }

我知道这不是你运行NHibernate的问题,但如果任何人有任何经验或建议来分享,我很乐意听到它。

我距离将审计记录写入队列的时间只有2秒,但我希望在放弃之前用尽所有可能性。

提前致谢,

史蒂夫


问题出自FlushMode.Commit :在这种模式下,NHibernate只会在提交事务时刷新一次会话。 所以冲洗后,不会冲洗另一次,冲洗后的任何更改都不会刷新。

要解决此问题,可以手动刷新会话,也可以更改为FlushMode.Auto 。 但是,如果使用Auto,请注意带有事件侦听器和/或拦截器的StackOverflowException,因为使用Auto时,NHibernate将在查询之前刷新,并因此调用OnFlushDirty ,因此如果在OnFlushDirty查询某些OnFlushDirty ,则会触发另一次刷新,然后在永无止境的循环中再次调用OnFlushDirty 。 为防止出现这种情况,您必须暂时将FlushMode更改为Never ,或者实施一个系统来确定已经处理了哪些更改,以避免一次又一次处理相同的更改。


我们以相同的方式处理审计(使用GUID PK)。 当使用Identity PK生成器时,每次调用Save都会立即发出INSERT,但是当使用GUID时,INSERTs只会在Flush期间执行。 我们通过修补NHibernate源码解决了这个问题。 在Flush方法的SessionImpl.cs中(第1467行左右),我添加了以下内容:

// Flush children when parent is flushed.
if (childSessionsByEntityMode != null) {
    foreach (var childSession in childSessionsByEntityMode) {
        childSession.Value.Flush();
    }
}
链接地址: http://www.djcxy.com/p/23237.html

上一篇: NHibernate Child Session not flushing properly

下一篇: Force query execution without flush/commit