3

我刚刚使用 MVC 3、Fluent nHibernate、AutoMapper 和 Autofac 建立了一个项目,利用了通用存储库、工作单元模式和 3 层设计。我现在遇到了这个问题:

我有一个工作单元,但我不知道在哪里/如何提交它。启动更容易;使用 Autofac,基于每个 HTTP 请求注入 - 我的工作单元的构造函数开始事务。然而,我意识到我最终得到了这样的商务课程:

private readonly IUnitOfWork _unitOfWork;
private readonly IUserRepository _userRepository;

public UserHandler(
    IUserRepository userRepository, 
    IUnitOfWork unitOfWork)
{
    _userRepository = userRepository;
    _unitOfWork = unitOfWork;
}

public void CreateUser(User user)
{
    // Fill the date fields
    user.CreationDt = DateTime.Now;
    user.ModifiedDt = DateTime.Now;

    // Add the user 
    _userRepository.Add(user);

    // Commit the changes
    _unitOfWork.Commit();
}

这很好,只要我不需要做任何其他交易。但是,如果在调用 .Add 之后,我决定用类似的方法调用另一个业务类怎么办?然后我有 2 次提交,我假设这会爆炸,因为我将尝试结束已经完成的事务。

我曾考虑将提交放在我的 UnitOfWork 的 Dispose 中,但如果发生异常,那将是个坏消息。我见过一些情况,人们也将他们的 UnitOfWork 注入到他们的控制器中,但这似乎是错误的,因为它破坏了关注点分离,您的控制器绕过业务层并直接调用数据库层。最后,我目前正在研究使用类似于 Sharp Architecture 中使用的属性但我也不确定这是否是正确的方法(再次,您不是让控制器直接访问/了解数据层吗?) .

有人可以分享一些关于我应该在哪里承诺的智慧吗?

4

2 回答 2

2

只要您在一个请求中共享您的数据库连接,您就可以开始事务并在响应发送到客户端后提交。我领导了一个特殊的动作过滤器来实现这一点。

public sealed class CommitOnSuccess : ActionFilterAttribute
{
    public IUnitOfWork UnitOfWork { get; set; }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        if (filterContext.Exception == null)
            UnitOfWork.Commit();
    }
}

这就是我如何使我的操作方法简单而轻量级

[CommitOnSuccess]
[HttpPost]
public ActionResult Create(ApplicationManagementViewModel model)
{

}

并且将对 Create 方法中从存储库中获得的实体执行更改

于 2012-06-25T19:35:17.333 回答
0

在应用程序结束请求中,您可以提交您的工作单元。在 global.asax.cs 文件中添加以下函数:

protected void Application_EndRequest(object sender, EventArgs e)
    {
     //code to commit unit of work
    }

此外,由于您使用的是 Autofac,您也可以将范围限定为IUnitOfWorkInstancePerLifetimeScope实现该类IDisposable,并且在您的Dispose函数中您可以提交您的会话。发生异常时这是怎么回事,您可以检查您的代码,如下所示:

 if ( HttpContext.Current != null && HttpContext.Current.Error != null) 
      transaction.Rollback();
 else
      transaction.Commit();
于 2012-06-25T19:18:56.137 回答