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

发布于 2024-11-28 09:12:03 字数 1638 浏览 2 评论 0原文

我已经遵循在此站点上的模式 将 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 模式,该方法确实为我的控制器中的每个方法调用beingtransaction。

i have followed the pattern on this site to hook up ninject and nhibernate to my asp.net-mvc3 site.

Here is the code in my 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();
       }

the issue is that i now need to do Update() and Add() in my controllers;

I have this as my controller code:

    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");
    }

my main question is that it feels wrong to pass in Iunitofwork in the constructor as many other actions don't need it. I only really need it for the actions where i do updates and inserts into my db. Since i am using ninject IOC on the link above it seems to say to pass this unitofwork object through IOC.

So, is there a better more optimized way to using the UnitOfWork pattern with IOC in asp.net-mvc that does call beingtransaction for every method in my controller.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

与酒说心事 2024-12-05 09:12:03

处理事务的另一种方法是使用 IActionFilter 在 OnActionExecuting 中打开事务并在 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");
}

An alternative way to handle transactions is to use an IActionFilter Open the transaction in OnActionExecuting and commit on 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();
        }
    }
}

Define an attribute to mark the actions that use a transaction:

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

Change your Ninject configuration:

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>();
    }
}

Finally change your controller:

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");
}
ㄟ。诗瑗 2024-12-05 09:12:03

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

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

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

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

I generally try to keep my generic IRepository implementation hidden inside the IUnitOfWork (see below).

My other recommendation is to pass a UnitOfWorkProvider or UnitOfWorkFactory to the constructor. That way you can register the transaction scope locally. This has the added benefit of being able to resolve the IRepository or ISession as you see fit, via dependency injection or manually.

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

Also make sure you in your IUnitOfWork.Dispose() you clean up the transaction and any data session objects / information you might have.

樱花坊 2024-12-05 09:12:03

我更喜欢只将我的工作单元注入到实际使用它们的类中。在大多数情况下,持久性类(在我的例子中为存储库)是唯一需要工作单元的类。您需要确保保持清晰的关注点分离。控制器不需要了解工作单元,也不应该与其耦合。

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

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

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

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

这有意义吗?

I prefer to only inject my unit of work into classes that actually use them. In most cases, the persistence classes (Repository in my case) are the only ones that need the unit of work. You want to make sure you maintain a clean separation of concerns. The controller doesn't need to know about the unit of work and shouldn't be coupled to it, either.

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

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

If you're invoking your repository from your controller, inject the repository into your controller as follows:

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

Does that make sense?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文