我们正在开发一个具有以下架构的.Net应用程序:表示层(使用带有ASP.Net MVC 2的MVC模式),服务层,数据访问层(使用实体框架上的存储库模式)。
我们决定将事务管理放在服务层中,但我们不确定如何实现它。我们希望完全在服务层级别控制事务。也就是说,每次控制器调用服务层中的方法时,它都必须是关于数据库更新的原子操作。
如果服务层中提供的不同服务之间没有关系,那么它很简单:每个方法都应该在执行结束时提交更改(即,在它使用的上下文中调用save方法)。但有时服务层的服务可以协同工作。
例如:我们提供具有确认方法的货运服务,该方法接收以下参数:货件ID,指示其是否对应于新客户或现有客户的标志,客户ID(如果货件确认是对于现有客户)和客户名称(如果是新客户)。如果该标志设置为“新客户”,则服务层必须(a)创建客户并(b)确认装运。对于(a)货运服务调用客户服务(已经实现了创建新客户并将其存储在数据库中所需的验证和逻辑)。
谁应该在这种情况下提交更改?
我们应该遵循这样的设计模式吗?
答案 0 :(得分:5)
我的服务上有一个Commit(),只有在服务创建UnitOfWork时才提交,如果在构造函数中传递,则提交不执行任何操作。
我为服务使用了第二个(内部)构造函数:
public class MyService
{
private IUnitOfWork _uow;
private bool _uowInternal;
public MyService()
{
_uow = new UnitOfWork();
_uowInternal = false;
}
internal MyService(IUnitOfWork uow)
{
_uow = uow;
_uowInternal = true;
}
public MyServiceCall()
{
// Create second service, passing in my UnitOfWork:
var svc2 = new MySecondService(_uow);
// Do your stuff with both services.
....
// Commit my UnitOfWork, which will include all changes from svc2:
Commit();
}
public void Commit()
{
if(!_uowInternal)
_uow.Commit();
}
}
答案 1 :(得分:1)
在使用WCF和L2S而不是EF的类似架构中,我们选择在主服务接口实现类中使用事务。我们使用TransactionScope来实现这一目标:
public void AServiceMethod() {
using(TransactionScope ts = new TransactionScope()) {
service1.DoSomething();
service2.DoSomething();
ts.Complete();
}
}
主要的缺点是交易可能会变大。在这种情况下,如果事务块中的一个服务调用仅需要只读访问,我们将其包装在嵌套的TransactionScope(TransactionScopeOption.Suppress)
块中,以防止在事务生命周期中进一步锁定行/表。