工作单元+存储库模式:业务交易概念的衰落

Ali*_*eza 56 c# java architecture unit-of-work repository-pattern

结合Unit of Work并且Repository Pattern是现在相当广泛使用的东西.正如Martin Fowler 所说,使用的目的UoW是形成商业交易,同时不知道存储库实际如何工作(持续无知).我已经回顾了很多实现; 并忽略具体细节(具体/抽象类,接口,......),它们或多或少类似于以下内容:

public class RepositoryBase<T>
{
    private UoW _uow;
    public RepositoryBase(UoW uow) // injecting UoW instance via constructor
    {
       _uow = uow;
    }
    public void Add(T entity)
    {
       // Add logic here
    }
    // +other CRUD methods
}

public class UoW
{
    // Holding one repository per domain entity

    public RepositoryBase<Order> OrderRep { get; set; }
    public RepositoryBase<Customer> CustomerRep { get; set; }
    // +other repositories

    public void Commit()
    {
       // Psedudo code: 
       For all the contained repositories do:
           store repository changes.
    }
}
Run Code Online (Sandbox Code Playgroud)

现在我的问题:

UoW公开公共方法Commit来存储更改.此外,由于每个存储库都有一个共享实例,因此每个存储库UoWRepository可以访问CommitUoW上的方法.通过一个存储库调用它会使所有其他存储库也存储其更改; 因此,整个交易概念崩溃的结果是:

class Repository<T> : RepositoryBase<T>
{
    private UoW _uow;
    public void SomeMethod()
    {
        // some processing or data manipulations here
        _uow.Commit(); // makes other repositories also save their changes
    }
}
Run Code Online (Sandbox Code Playgroud)

我认为这一定是不允许的.考虑到UoW(业务事务)的目的,该方法Commit应仅暴露给启动业务事务的人,例如业务层.让我感到惊讶的是,我找不到任何解决这个问题的文章.在所有这些中Commit都可以通过注入的任何回购来调用.

PS:我知道我可以告诉我的开发人员不要打电话CommitRepository一个受信任的架构比可靠的开发人员更可靠!

And*_*bel 27

我同意你的担忧.我更喜欢有一个环境工作单元,其中打开工作单元的最外层函数是决定是提交还是中止的工作单元.调用的函数可以打开一个工作范围单元,如果有的话,它会自动登记在环境UoW中,如果没有,则创建一个新的工作范围.

UnitOfWorkScope我使用的实现很大程度上取决于TransactionScope工作原理.使用环境/范围方法也消除了依赖注入的需要.

执行查询的方法如下所示:

public static Entities.Car GetCar(int id)
{
    using (var uow = new UnitOfWorkScope<CarsContext>(UnitOfWorkScopePurpose.Reading))
    {
        return uow.DbContext.Cars.Single(c => c.CarId == id);
    }
}
Run Code Online (Sandbox Code Playgroud)

写入的方法如下所示:

using (var uow = new UnitOfWorkScope<CarsContext>(UnitOfWorkScopePurpose.Writing))
{
    Car c = SharedQueries.GetCar(carId);
    c.Color = "White";
    uow.SaveChanges();
}
Run Code Online (Sandbox Code Playgroud)

请注意,uow.SaveChanges()如果这是根(最))范围,则调用将仅对数据库进行实际保存.否则,它被解释为"okay vote",允许根范围保存更改.

整个实施UnitOfWorkScope可在以下网址获得:http://coding.abel.nu/2012/10/make-the-dbcontext-ambient-with-unitofworkscope/

  • 我读了它,看到有人有类似的担忧我真的松了一口气.但我想知道为什么不使用`TransactionScope`?它更方便,使得架构更加灵活,可以在以后进行扩展和更改.此外,您在运行时阻止了对"ReadOnly UoW"的"SaveChanges"调用.那没关系,但我对此感觉不好.老实说,我认为存储库消耗的"UoW"不应该向他们公开`SaveChanges`. (3认同)

Cha*_*lky 10

使您的存储库成为您UoW的成员.不要让你的存储库'看到'你的UoW.让UoW处理交易.

  • 在我看来,你已经重新思考了太多。UoW 不存在“标准”(或完美)实现,因为该实现在某种程度上取决于所使用的 ORM。但我认为您在回答中很好地抓住了该模式的意图。 (2认同)

lig*_*cko 2

在 .NET 中,数据访问组件通常会自动加入环境事务。因此,在事务内保存更改提交事务以持久化更改是分开的。

换句话说 - 如果您创建一个事务范围,您可以让开发人员节省尽可能多的费用。直到事务提交后,数据库的可观察状态才会更新(当然,可观察的状态取决于事务隔离级别)。

这显示了如何在 C# 中创建事务范围:

using (TransactionScope scope = new TransactionScope())
{
    // Your logic here. Save inside the transaction as much as you want.

    scope.Complete(); // <-- This will complete the transaction and make the changes permanent.
}
Run Code Online (Sandbox Code Playgroud)