我有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。
答案 0 :(得分:12)
处理交易的另一种方法是使用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");
}
答案 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) {...}
}
这有意义吗?