6

在 Web 应用程序中使用 Autofac 管理 NHibernate 事务的最佳方法是什么?

我的会话方法是

builder.Register(c => c.Resolve<ISessionFactory>().OpenSession())
       .ContainerScoped();

对于ITransaction,我在 Google Code 上找到了一个示例,但它依赖于HttpContext.Current.Error决定是否回滚。

有更好的解决方案吗?NHibernate 事务应该有什么范围?

4

3 回答 3

4

我前一阵子发过这个:

http://groups.google.com/group/autofac/browse_thread/thread/f10badba5fe0d546/e64f2e757df94e61?lnk=gst&q=transaction#e64f2e757df94e61

修改,使拦截器具有日志记录能力,并且 [Transaction] 属性也可以在类上使用。

[global::System.AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class TransactionAttribute : Attribute
{
}


public class ServicesInterceptor : Castle.Core.Interceptor.IInterceptor
{
    private readonly ISession db;
    private ITransaction transaction = null;

    public ServicesInterceptor(ISession db)
    {
        this.db = db;
    }

    public void Intercept(IInvocation invocation)
    {
        ILog log = LogManager.GetLogger(string.Format("{0}.{1}", invocation.Method.DeclaringType.FullName, invocation.Method.Name));

        bool isTransactional = IsTransactional(invocation.Method);
        bool iAmTheFirst = false;

        if (transaction == null && isTransactional)
        {
            transaction = db.BeginTransaction();
            iAmTheFirst = true;
        }

        try
        {
            invocation.Proceed();

            if (iAmTheFirst)
            {
                iAmTheFirst = false;

                transaction.Commit();
                transaction = null;
            }
        }
        catch (Exception ex)
        {
            if (iAmTheFirst)
            {
                iAmTheFirst = false;

                transaction.Rollback();
                db.Clear();
                transaction = null;
            }

            log.Error(ex);
            throw ex;
        }
    }

    private bool IsTransactional(MethodInfo mi)
    {
        var atrClass = mi.DeclaringType.GetCustomAttributes(false);

        foreach (var a in atrClass)
            if (a is TransactionAttribute)
                return true;

        var atrMethod = mi.GetCustomAttributes(false);

        foreach (var a in atrMethod)
            if (a is TransactionAttribute)
                return true;

        return false;
    }
}
于 2009-11-01T17:13:23.743 回答
4

当我使用 autofac 时,我使用相同的容器作用域方法,但不是将相同的会话传递给我的存储库/DAO 对象,而是传递一个容器作用域的 UnitOfWork。工作单元在构造函数中有这个。

    private readonly ISession _session;
    private ITransaction _transaction;

    public UnitOfWork(ISession session)
    {
        _session = session;
        _transaction = session.BeginTransaction();
    }

处置是:

    public void Dispose()
    {
        try
        {
            if (_transaction != null &&
                            !_transaction.WasCommitted &&
                            !_transaction.WasRolledBack)
                _transaction.Commit();
            _transaction = null;
        }
        catch (Exception)
        {
            Rollback();
            throw;
        }

    }

我正在(ab)使用 autofac 中的确定性处理东西来管理它,而且我有点喜欢它。

另一件事是,我基本上只针对 ASPNet 环境,并有意识地决定事务与 Web 请求相关联。因此,每个 Web 请求模式的事务。

因此,我可以在 IHttpModule 中执行此错误处理代码:

    void context_Error(object sender, System.EventArgs e)
    {
        _containerProvider.RequestContainer.Resolve<IUnitOfWork>().Rollback();
    }

我还没有仔细研究过 NHibernate.Burrow,但我确信那里有一些东西可以完成大部分工作。

于 2009-11-04T15:25:50.647 回答
-1

我通常自己管理交易..

public ActionResult Edit(Question q){
try {
 using (var t = repo.BeginTransaction()){
  repo.Save(q);
  t.Commit();
  return View();
 }
 catch (Exception e){
  ...
 }
}
于 2009-10-30T21:49:39.557 回答