你应该如何在我的asp.net-mvc网站上使用UnitofWork模式(使用nhibernate和ninject)

时间:2011-08-06 14:20:09

标签: nhibernate asp.net-mvc-3 ioc-container ninject unit-of-work

我有followed the pattern on this site将ninject和nhibernate连接到我的asp.net-mvc3网站。

以下是我的global.aspx.cs中的代码:

 internal class ServiceModule : NinjectModule
{
    public override void Load()
    {
        var helper = new NHibernateHelper(connectionString);
        Bind<ISessionFactory>().ToConstant(helper.SessionFactory)
            .InSingletonScope();

        Bind<IUnitOfWork>().To<UnitOfWork>()
            .InRequestScope();
        Bind<ISession>().ToProvider(new SessionProvider())
            .InRequestScope();
        Bind<IIntKeyedRepository<FAQ>>().To<Repository<FAQ>>()
            .InRequestScope();
       }

问题是我现在需要在我的控制器中执行Update()和Add();

我将此作为我的控制器代码:

    public FAQController(IIntKeyedRepository<FAQ> faqRepository, IUnitOfWork unitOfWork)
    {
        _faqRepository = faqRepository;
        _unitOfWork = unitOfWork;
    }


  [Authorize]
    [AcceptVerbs(HttpVerbs.Post)]
    [ValidateInput(false)]
    public ActionResult AddFAQ(FAQ contact)
    {
        var c = new FAQ {Question = contact.Question, Answer = contact.Answer};
        _faqRepository.Add(c);
        _unitOfWork.Commit();
        return RedirectToAction("Index");
    }

我的主要问题是,在构造函数中传递Iunitofwork感觉不对,因为许多其他操作不需要它。我只是需要它来执行更新和插入我的数据库的操作。由于我在上面的链接上使用ninject IOC,似乎可以说通过IOC传递这个单元工作对象。

那么,在asp.net-mvc中使用带有IOC的UnitOfWork模式是否有更好的更优化方式,它可以为我的控制器中的每个方法调用istransaction。

3 个答案:

答案 0 :(得分:12)

处理交易的另一种方法是使用IActionFilterOnActionExecuting中打开交易并在OnActionExecuted上提交

public class TransactionFilter : IActionFilter
{
    private readonly ISession session;
    private ITransaction transaction;

    public TransactionFilter(ISession session)
    {
        this.session = session;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        this.transaction = this.session.BeginTransaction();
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        try
        {
            if (this.transaction.IsActive)
            {
                if (filterContext.Exception == null)
                {
                    this.transaction.Commit();
                }
                else
                {
                    this.transaction.Rollback();
                }
            }
        }
        finally
        {
            this.transaction.Dispose();
        }
    }
}

定义一个属性以标记使用事务的操作:

[AttributeUsage(AttributeTargets.Method)]
public class TransactionAttribute : Attribute
{ 
}

更改您的Ninject配置:

internal class ServiceModule : NinjectModule
{
    public override void Load()
    {
        var helper = new NHibernateHelper(connectionString);
        Bind<ISessionFactory>().ToConstant(helper.SessionFactory)
            .InSingletonScope();

        Bind<ISession>().ToProvider<SessionProvider>().InRequestScope();
        Bind(typeof(IRepository<>)).To(typeof(Repository<>));
        Bind(typeof(IIntKeyedRepository<>)).To(typeof(Repository<>));
        BindFilter<TransactionFilter>(FilterScope.Action, null)
            .WhenActionMethodHas<TransactionAttribute>();
    }
}

最后改变你的控制器:

public FAQController(IIntKeyedRepository<FAQ> faqRepository)
{
    _faqRepository = faqRepository;
}


[Transaction]
[Authorize]
[AcceptVerbs(HttpVerbs.Post)]
[ValidateInput(false)]
public ActionResult AddFAQ(FAQ contact)
{
    var c = new FAQ {Question = contact.Question, Answer = contact.Answer};
    _faqRepository.Add(c);
    return RedirectToAction("Index");
}

答案 1 :(得分:0)

我通常会尝试将我的通用IRepository实现隐藏在IUnitOfWork中(见下文)。

我的另一个建议是将UnitOfWorkProvider或UnitOfWorkFactory传递给构造函数。这样您就可以在本地注册事务范围。这样做的另一个好处是能够通过依赖注入或手动解析IRepository或ISession。

using(var uow = this.UnitOfWorkProvider.New())
{
    uow.Save<Faq>(myFaq);
}

另外,请确保您在IUnitOfWork.Dispose()中清理事务以及您可能拥有的任何数据会话对象/信息。

答案 2 :(得分:0)

我更喜欢只将我的工作单元注入实际使用它们的类中。在大多数情况下,持久性类(在我的情况下是Repository)是唯一需要工作单元的类。您希望确保保持清晰的关注点分离。控制器不需要知道工作单元,也不应该与它耦合。

public class FaqRepository {
  public FaqRepository(IUnitOfWork unitofWork) { ... }

  public void CreateQuestion(Faq faq) {
    unitOfWork.Save(faq);
    unitOfWork.Commit();
  }
}

如果您从控制器调用存储库,请将存储库注入控制器,如下所示:

public class FaqController {
  public FaqController(IFaqRepository faqRepository) {...}
}

这有意义吗?