虽然对Webforms和Linq非常熟悉,但我是ASP.NET MVC和NHibernate World的新手。我一直在使用Bob Cravens'examples完成一个项目。我的应用程序主要是读取和非顺序写入,因此通常我不会使用事务。但是为了实现工作单元模式,包括Ayende's blog在内的所有研究都说我应该。
我遇到的问题是这个 -
我正在考虑向UnitOfWork添加一个bool“CommitNeeded”,它将由我的Save()方法设置并有条件地触发UnitOfWork.Dispose()上的Commit()。这是一个好主意吗?
我应该删除交易基础设施吗?我应该将Commit()改为Flush()吗?
任何有助于修复我的反模式的建议都将受到赞赏。
回应评论 - 我想我不介意它们是一起发生还是分开发生。有两件事情在发生。第一个更改“客户”对象,然后保存它。第二个创建一个日志记录条目,然后调用相同的“保存”方法。
var Customer = ServiceLayer.GetCustomer(...);
Transmogrify(Customer, Customer.Children, Widgets, ...);
ServiceLayer.Save(Customer)
ServiceLayer.RecordEvent(Customer, "Customer was frobbed")
其中LogEvent看起来像
public void RecordEvent(Customer customer, int eventTypeId, string description)
{
...
Save(customer);
}
RecordEvent方法有自己的“保存”,因为它是从没有数据更改的其他控制器调用的。我相信保存电话不属于这两个地方。问题是,在哪里?服务层的Dispose()方法?或像其他用户建议的过滤器?
答案 0 :(得分:5)
使用ASP.NET MVC,我使用动作过滤器将事务范围绑定到控制器操作执行生命周期。这在大多数情况下都很有用,但是你必须小心谨慎,不要让交易开放太长时间。
public class UnitOfWorkActionFilter : ActionFilterAttribute
{
public IUnitOfWork UnitOfWork { get; set; }
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
UnitOfWork.Start();
base.OnActionExecuting(filterContext);
}
public override void OnActionExecuted(ActionExecutedContext filterContext)
{
if (filterContext.Exception == null)
{
UnitOfWork.Commit();
}
else
{
UnitOfWork.Rollback();
}
UnitOfWork.Dispose();
base.OnActionExecuted(filterContext);
}
}
在我的情况下,我通过自定义ControllerActionInvoker
使用属性注入来获取IUnitOfWork
的{{1}}依赖项。
答案 1 :(得分:1)
我正在使用这个http模块。我在http请求开始时获取事务,并在http请求结束时终止它:
public class UnitOfWorkModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += context_BeginRequest;
context.EndRequest += context_EndRequest;
}
private void context_BeginRequest(object sender, EventArgs e)
{
IUnitOfWork instance = UnitOfWorkFactory.GetDefault();
instance.Begin();
}
private void context_EndRequest(object sender, EventArgs e)
{
IUnitOfWork instance = UnitOfWorkFactory.GetDefault();
try
{
instance.Commit();
}
catch
{
instance.RollBack();
}
finally
{
instance.Dispose();
}
}
}
我的工作单元工厂只是在IoC容器中注册类型时初始化的Func:
public class UnitOfWorkFactory
{
public static Func<IUnitOfWork> GetDefault;
}
初始化(对于我的案例StructureMap):
UnitOfWorkFactory.GetDefault = () => container.GetInstance<IUnitOfWork>();
然后在UnitOfWorkModule web.config
中注册<httpModules>
<add name="UnitOfWorkModule" type="UI.UnitOfWorkModule, UI" />
</httpModules>