我在这里正确使用nHIbernate ITransaction吗?

时间:2012-06-13 20:54:19

标签: asp.net nhibernate transactions

我只是在学习nHibernate并且遇到了可能需要解决的简单问题。

是的,所以到目前为止我已经想到你不能/不应该把nHibernate交易嵌套在彼此之内;在我的情况下,当范围转到另一个例程并且我开始一个新的事务时,我想出了这个。

我应该做以下事情吗?

using (ITransaction transaction = session.BeginTransaction())
{
    NHibernateMembership mQuery =
        session.QueryOver<NHibernateMembership>()
            .Where(x => x.Username == username)
            .And(x => x.ApplicationName == ApplicationName)
            .SingleOrDefault();

    if (mQuery != null)
    {
        mQuery.PasswordQuestion = newPwdQuestion;
        mQuery.PasswordAnswer = EncodePassword(newPwdAnswer);
        session.Update(mQuery);

        transaction.Commit();
        passwordQuestionUpdated = true;
    }
}

// Assume this is in another routine elsewhere but being
// called right after the first in the same request
using (ITransaction transaction = session.BeginTransaction())
{
    NHibernateMembership mQuery =
        session.QueryOver<NHibernateMembership>()
            .Where(x => x.Username == username)
            .And(x => x.ApplicationName == ApplicationName)
            .SingleOrDefault();

    if (mQuery != null)
    {
        mQuery.PasswordQuestion = newPwdQuestion;
        mQuery.PasswordAnswer = EncodePassword(newPwdAnswer);
        session.Update(mQuery);

        transaction.Commit();
        passwordQuestionUpdated = true;
    }
}

注意:我知道它们只是一个副本,我只是在展示我的问题

第一个问题 这是否意味着要做到这一点?每次操作交易?

第二个问题 我需要调用transaction.Commit();每次还是只在最后一次?

第三个问题 有没有更好的方法,自动化或手动,这样做?

第三个问题 我可以使用session.Transaction.IsActive来确定“当前会话”是否已经是事务的一部分 - 所以在这种情况下我可以在最高级别进行“事务处理”,比如说Web表单代码,然后让例程在其中调用,然后在最后完成所有工作。这是一种有缺陷的方法吗?

我真的想要把它打倒,所以我开始,因为我的意思是继续;我不想找到1000行代码,我需要更改它们。

提前致谢。

修改

是的,所以我写了一些代码来解释我的问题。

private void CallingRoutine()
{
    using(ISession session = Helper.GetCurrentSession)
    {
        using (ITransaction transaction = session.BeginTransaction())
        {
            //  RUN nHIbernate QUERY to get an OBJECT-1

            //  DO WORK on OBJECT

            //  Need to CALL an EXTERNAL ROUTINE to finish work
            ExternalRoutine();

            //  DO WORK on OBJECT-1 again

            //  *** At this point ADO exception triggers
        }
    }
}

private bool ExternalRoutine()
{
    using(ISession session = Helper.GetCurrentSession)
    {
        using (ITransaction transaction = session.BeginTransaction())
        {
            //  RUN nHIbernate QUERY to get an OBJECT-2

            //  DO WORK on OBJECT

            //  Determine result
            if(Data)
            {
                return true;
            }

            return false;
        }
    }
}

希望这证明了这个问题。这是我理解编写事务的方式,但注意ADO异常是如何发生的。我显然做错了什么。我是怎么写这些例程的?

例如,如果我要为某个提供程序编写一个帮助程序对象,并且在每个公开的例程中都有一个nHibernate查询运行 - 我如何编写这些例程,就事务而言,假设我对调用函数一无所知,数据 - 我的工作是有效地使用nHibernate并返回结果。

这就是我通过编写事务我在ExternalRoutine()中所做的假设 - 假设这是nHibernate的唯一用途并明确地进行事务。

1 个答案:

答案 0 :(得分:0)

如果可能,我建议使用System.Transactions.TransactionScope:

using(var trans = new TransactionScope()) 
using(var session = .. create your session...) {
    ... do your stuff ...
    trans.Complete();
}

trans.Complete将导致会话刷新并提交事务,此外您还可以使用嵌套的事务管理器。对此唯一的“缺点”是,如果你有多个连接(或MSMQ等入伍资源),它将升级到DTC,但这不一定是一个缺点,除非你使用像MySQL这样不能很好地使用的东西。 DTC。

对于简单的情况,我可能会在BeginRequest中使用事务范围,如果没有错误则在EndRequest中提交它(如果你使用ASP.NET MVC则使用过滤器),但这实际上很大程度上取决于什么你正在做 - 只要你的操作很短(他们应该在网络应用程序中),这应该没问题。创建会话和事务范围的开销并不大,它应该导致访问静态资源(或不需要会话的资源)的问题,除非您正在查看真正高容量/高性能的网站。 / p>