工作单位的实际用途&存储库模式

时间:2011-05-19 09:40:41

标签: orm domain-driven-design repository-pattern unit-of-work domain-model

我正在构建一个ORM,并试图找出每个模式的确切职责。假设我想在两个帐户之间转移资金,使用工作单元来管理单个数据库事务中的更新。 以下方法是否正确?

  1. 从存储库中获取它们
  2. 将它们附加到我的工作单元
  3. 做生意交易&提交?
  4. 示例:

    from = acccountRepository.find(fromAccountId);
    to = accountRepository.find(toAccountId);
    
    unitOfWork.attach(from);
    unitOfWork.attach(to);    
    
    unitOfWork.begin();
    from.withdraw(amount);
    to.deposit(amount);
    unitOfWork.commit();
    

    如本例所示,应单独使用工作单元和存储库,或者:

    • 工作单元是否应在内部使用存储库并且能够加载对象?
    • ...或者存储库是否应在内部使用工作单元并自动附加任何已加载的实体?

    欢迎所有评论!

3 个答案:

答案 0 :(得分:16)

简短的回答是存储库将以某种方式使用UoW,但我认为这些模式之间的关系不像最初看起来那么具体。工作单元的目标是创建一种将一组数据库相关函数基本上混为一谈的方法,以便它们可以作为原子单元执行。使用UoW时创建的边界与事务创建的边界之间通常存在关系,但这种关系更为巧合。

另一方面,存储库模式是一种通过聚合根创建类似于集合的抽象的方法。通常,您在存储库中看到的各种事物与查询或查找聚合根的实例有关。一个更有趣的问题(并且没有一个答案的问题)是添加除了查询聚合之外的其他方法的方法是否有意义。一方面,可能存在一些有效的情况,其中您有适用于多个聚合的操作。另一方面可以说,如果您在多个Aggregate上执行操作,那么您实际上是在另一个Aggregate上执行单个操作。如果您只是查询数据,我不知道您是否真的需要创建UoW隐含的边界。这一切都归结为领域以及它是如何建模的。

这两种模式处理的是非常不同的抽象层次,而工作单元的参与将取决于聚合体的建模方式。聚合可能希望将与持久性相关的工作委托给其管理的实体,或者聚合与实际ORM之间可能存在另一层抽象。如果您的聚合/实体本身正在处理持久性,那么存储库也可能适合管理该持久性。如果没有,那么将UoW包含在您的存储库中是没有意义的。

如果您想在组织外部为公众消费创建一些内容,那么我建议您创建Repository接口/基础实现,以便它们可以直接与您的ORM交互,具体取决于需求您的ORM用户。如果这是内部的,并且您在Aggregates.Entities中执行持久性工作,那么您的存储库可以使用您的UoW。对于通用存储库,从存储库实现中提供对UoW对象的访问是有意义的,这可以确保对其进行初始化和适当处理。在这方面,有时您可能希望在单个UoW边界内使用多个存储库,因此在这种情况下您希望能够将已经准备好的UoW传递到存储库。

答案 1 :(得分:4)

我建议您在内部使用UoW时使用方法。这种方法有一些优点,特别是对于Web应用程序。

在Web应用程序中,使用UoW的推荐模式是每个HTTP请求的工作单元(会话)。因此,如果您的存储库将共享UoW,您将能够对其他存储库请求的对象(如多个聚合引用的数据字典)使用第一级缓存(使用标识映射)。此外,您只需要提交一个事务而不是多个事务,因此在性能方面它会更好。

你可以看看在Java / .NET世界中成熟的ORM的Hibernate / NHibernate源代码。

答案 2 :(得分:2)

好问题!

取决于您的工作边界。如果它们将跨越多个存储库,那么您可能必须创建另一个抽象来确保涵盖多个存储库。它就像一个在域驱动设计中定义的小“服务”层。

如果您的工作单元几乎是每个存储库,那么我会使用第二个选项。

然而,我的问题是,在编写ORM时,您如何担心存储库?它们将由您的工作单位的消费者定义和使用吗?如果是这样,您别无选择,只能提供一个工作单元,您的消费者必须在您的工作单元中登记存储库,并且还负责控制工作单元的边界。不是吗?