使用 Nhibernate 静默插入失败

Insert silently fail with Nhibernate

我的 NHibernate 插入有问题

交易开始顺利, 我的 select 正确完成, 我的 select 序列中的下一个值也是, 并提交交易, 但是我的 NHprofiler 中没有插入内容,也没有出现错误。 我使用 Session.OpenSession(ReadCommited) & Transaction 知道会发生什么吗?

代码

class NHUnitOfWok : INHibernateUnitOfWork
{
    private readonly ISession _session;
    private bool _isDisposed;
    private IsolationLevel _isolationLevel;

    public NHUnitOfWok(ISession session)
    {
        _session = session;
        _session.FlushMode = FlushMode.Never;
        _isolationLevel = IsolationLevel.ReadCommitted;
    }

    internal ISession Session
    {
        get { return _session; }
    }

    public void SaveChanges()
    {
        Session.Flush();
    }

    public void CancelChanges()
    {
        Session.Clear();
    }

    public void Commit()
    {
        Session.Transaction.Commit();
    }

    public void Rollback()
    {
        Session.Transaction.Rollback();
    }


    public void WithinNewSession(Action<ISession> actionToExecute, IsolationLevel? isolationLevel = null)
    {
        using (var tempSession = Session.SessionFactory.OpenSession())
        {
            using (var transaction = tempSession.BeginTransaction(isolationLevel ?? _isolationLevel))
            {
                actionToExecute(tempSession);
                transaction.Commit();
            }
        }
    }

    public void WithinTransaction(Action action, IsolationLevel? isolationLevel = null)
    {
        Enforce.NotNull(action, "action");

        WithinTransaction<object>(() =>
        {
            action();
            return null;
        });
    }

    public T WithinTransaction<T>(Func<T> func, IsolationLevel? isolationLevel = null)
    {
        Enforce.NotNull(func, "func");

        if (Session.Transaction != null && Session.Transaction.IsActive)
        {
            return func.Invoke();
        }

        using (var localTran = Session.BeginTransaction(isolationLevel ?? _isolationLevel))
        {
            try
            {
                var funcRes = func.Invoke();
                localTran.Commit();

                return funcRes;
            }
            catch (TransactionException ex)
            {
                throw new DataException(Resource.TransactionException, ex);
            }
            catch (Exception ex)
            {
                if (Session.Transaction.IsActive)
                    localTran.Rollback();
                throw new DataException(Resource.TransactionException, ex);
            }
        }
    }

    public bool IsStarted()
    {
        return Session.Transaction != null && Session.Transaction.IsActive;
    }

    public void Start()
    {
        if (Session.Transaction == null || !Session.Transaction.IsActive)
        {
            Session.BeginTransaction(_isolationLevel);
        }
    }

    private void Dispose(bool disposing)
    {
        if (!disposing || _isDisposed)
        {
            return;
        }
        _isDisposed = true;
    }

    #region IDisposable Members

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    #endregion
}

FlushMode.Never 可能适用于只读事务,但对于其他任何事务,嗯,可能不是。它的 xml 文档指出:

The ISession is never flushed unless Flush() is explicitly called by the application. This mode is very efficient for read only transactions.

所以不要默认使用它。
至少这是我的建议。我知道出于 "performance" 的原因,有一些潜伏的建议可以使用它,但是通过注释掉它来检查你是否还有问题。
无论如何,我从不首先优化 运行-time 性能,我认为开发人员性能应该是优先考虑的。 (除非应用程序有实际的、经过验证的和相应的 运行 时间性能问题。或者,当然,当代码在 运行 时间执行复杂性方面是一个明显的编码恐怖时,例如无动机的 O (n²) 算法或最差算法。)

如果您想坚持使用该模式,请在提交交易前在会话中调用 Flush(或如所写 ,选择 FlushMode.Commit)。但实际上,这种选择是开发人员不得不使用它的陷阱。

查看默认模式文档,Auto:

The ISession is sometimes flushed before query execution in order to ensure that queries never return stale state. This is the default flush mode.

您是否愿意冒因在某些数据更改后同一会话中发生的查询中出现意外过时数据而出现细微错误的风险?

旁注:为什么 "complicating" 代码带有 Invoke?见 this.