同一事务下的多个存储库

时间:2018-03-14 05:34:49

标签: architecture repository domain-driven-design cqrs

想象一下当应用程序层打开一个新事务并且您希望在此事务下执行两个存储库操作时的情况。假设我想添加一个带有IUserRepository的新用户,然后保存在用户域模型状态更改期间生成的所有事件。我在ApplicationLayer(TransactionScope)中打开一个新事务,然后执行这两个操作。但是,如果我想将存储库实现更改为FileBasedRepository或HttpCloudRepository,那该怎么办?存储库不知道它们是在某些事务下运行的事实,还是它们应该存在? 主要问题是关于抽象。我们都努力根据抽象编写代码。我看到的是,如果我实现了一个工作单元,并且我在应用程序层使用2个存储库更新2个聚合(存储库使用MSSql),那么我无法将其中一个存储库实现更改为httpbased或基于内存。问题是如何编写这样的代码。好像我必须在事务上创建一个抽象,并为HttpUnitOfWork实现我自己的回滚。感觉像我的初始工作单元与db紧密耦合,并且可以重命名为DbUnitOfWork。但这又错了,因为没有sql数据库,根本不支持事务。

3 个答案:

答案 0 :(得分:2)

  

存储库不知道它们是在某些交易下运行的,还是它们应该运行?

这是Evan在Blue Book

中所写的内容
  

REPOSITORY概念适用于许多情况。实施的可能性是如此多样化,我只能列出一些需要考虑的问题....   将事务控制留给客户端。虽然REPOSITORY将从数据库中插入和删除,但它通常不会提交任何内容....如果REPOSITORY保持其关闭,事务管理将更简单。

说实话,我觉得这个概念很难与同一章的其他着作相协调。

  

对于需要全局访问的每种类型的对象,创建(一个REPOSITORY)可以提供该集合中所有对象的内存中集合的错觉。

在我通常使用的语言中,内存中的集合通常管理自己的状态。是不是暗示交易控制应该在收集界面后面,而不是留给客户?

另一点是我们的持久性解决方案变得更加复杂;对于Evans,域模型仅管理对单个数据库的写入,该数据库支持可跨越多个聚合的事务(即,RDBMS)。但如果你改变了这个假设,那么很多事情就会变得更加复杂。

提供了一些提示。从存储库中读取很漂亮;您将实现的所有复杂性隐藏在一些持久性不可知的外观背后。写作可能比较棘手 - 如果您的域模型需要支持将多个聚合一起保存(同一事务),那么您的"存储库"界面应该明确。

现在,您可能会看到更多支持这样的想法,即聚合的修改应始终在单独的事务中进行。这减轻了存储库协调的压力。

答案 1 :(得分:1)

存储库和交易

对我而言,存储库不应该知道环境事务 - 应该有一个类似工作单元的容器,它可以跟踪更新的实体并在您声明工作单元完成时提交事务。

包含其他来源的存储库

在同一工作单元中混合来自不同来源的存储库的数据不应该是一个问题。 理想情况下,UoW会知道哪种持久性机制与哪种类型的实体有关并最终对其进行排序。

但是出于实际原因,您可能希望将UoW限制为单个持久性存储(通常是通过ORM的数据库),并添加到具有不同的事务非文本数据源方法的存储库,如Update(entity)在被叫时直接到源。

答案 2 :(得分:1)

存储库不知道使用它的上下文。因此,存储库不应负责启动,提交或回滚事务。

因此,我总是将UnitOfWork / DbSession /的任何内容传递给我的存储库。存储库使用UnitOfWork,事务在存储库外部提交。

在伪代码中,这看起来像这样:

var uow = DatabaseContext.CreateUnitOfWork();

uow.StartTransaction();

var productRepository = new ProductRepository(uow);
var customerRepository = new CustomerRepository(uow);

// ... do some operations on the repositories.

uow.Commit();