【问题标题】:Practical usage of the Unit Of Work & Repository patterns工作单元和存储库模式的实际使用
【发布时间】:2011-08-28 17:44:51
【问题描述】:

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

  1. 从存储库中获取它们
  2. 将它们附加到我的工作单元
  3. 进行业务交易并提交?

例子:

from = acccountRepository.find(fromAccountId);
to = accountRepository.find(toAccountId);

unitOfWork.attach(from);
unitOfWork.attach(to);    

unitOfWork.begin();
from.withdraw(amount);
to.deposit(amount);
unitOfWork.commit();

应该像本例一样,独立使用工作单元和存储库,或者:

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

欢迎所有的cmets!

【问题讨论】:

  • 只是好奇,既然有好几个 ORM,为什么还要构建 ORM?
  • 只是尝试将 ORM 最佳实践应用于 PHP。已经有一些,但与我的期望不完全相符。
  • 感谢我发现了这样的问题 +1

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


【解决方案1】:

好问题!

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

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

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

【讨论】:

  • 谢谢尼莱什。实际上,我的计划是为所有这些模式定义一个干净的接口,以及一个旨在非常通用并适应我们日常工作的大多数情况的基本实现。我已经有了一个可行的实现,模型和数据映射器以及一个映射器注册表,它提供对单个类中所有映射器的访问;但我正在尝试突破界限,为包含身份映射的存储库提供支持,支持标准搜索和工作单元,以管理数据库更新和处理事务。
  • 抱歉这么冗长,我需要更多空间 :) 所以我想找到一个关于如何将它们放在一起的通用想法!非常感谢您的帮助。
【解决方案2】:

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

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

您可以查看 Hibernate/NHibernate 源代码,它们是 Java/.NET 世界中成熟的 ORM。

【讨论】:

    【解决方案3】:

    简短的回答是存储库会以某种方式使用 UoW,但我认为这些模式之间的关系不像最初看起来那样具体。工作单元的目标是创建一种将一组与数据库相关的功能集中在一起的方法,以便它们可以作为一个原子单元执行。使用UoW时创建的边界和交易创建的边界之间往往存在关系,但这种关系更多的是巧合。

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

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

    如果您想为组织外部的一般公众使用创建一些东西,那么我建议您创建存储库接口/基础实现的方式允许它们直接与您的 ORM 交互或不根据需要进行交互你的 ORM 的用户。如果这是内部的,并且您正在 Aggregates.Entities 中进行持久性工作,那么您的存储库使用您的 UoW 是有意义的。对于通用存储库,从存储库实现中提供对 UoW 对象的访问是有意义的,这可以确保它被适当地初始化和处置。需要注意的是,有时您可能希望在单个 UoW 边界内使用多个存储库,因此在这种情况下,您可能希望能够将已经准备好的 UoW 传递给存储库。

    【讨论】:

    • 感谢您的完整回答。总而言之,没有“最好”的方式来做到这一点,这是在 ORM 的全局上下文中的选择问题。
    猜你喜欢
    • 1970-01-01
    • 2016-01-15
    • 1970-01-01
    • 1970-01-01
    • 2013-02-05
    • 1970-01-01
    • 1970-01-01
    • 2014-12-27
    相关资源
    最近更新 更多