【问题标题】:In DDD, are repositories the only type of classes which can touch persistence?在 DDD 中,存储库是唯一可以触及持久性的类吗?
【发布时间】:2016-02-29 11:26:39
【问题描述】:

在 DDD 中,聚合根通过存储库进行持久化。但是存储库是唯一可以在有界上下文中触及持久性的类吗?

我在 DDD 旁边使用 CQRS。在查询方面,诸如视图计数、赞成票之类的东西需要持久化,但我觉得将它们建模为聚合根很尴尬。我将 DDD 聚合根建模限制在命令端。查询端不允许使用存储库。但是查询端经常要求少量的持久化能力。

另外,我正在使用域事件,某些域事件也需要持久化。我需要一种叫做事件存储的东西,但我只听说事件溯源 (ES) 中出现了这样的术语,我没有使用 ES。

如果确实需要这样的持久类。如何称呼它们,它们应该属于哪一层?

[更新]

当我阅读下面的答案时,我意识到我的问题有点模棱两可。 我主要指的是写(也包括读)。

谢谢。

【问题讨论】:

  • 我相信你需要务实而不是教条。如果您需要保存事件,请保存事件。您不需要存储库,因为存储库仅用于聚合。您可以将事件发送到消息总线中,并将它们保存在某个单独的进程中。但确实查询是查询,默认情况下它们不能保存任何东西,除非你想在那里记录一些东西。查询是幂等的,它们不会改变状态并且没有副作用。
  • @AlexeyZimarev 我理解你所说的保存事件。我也明白查询不应该改变状态。但是那些改变状态但难以将它们建模为聚合根中的值对象的东西呢?比如视图计数和赞成票?
  • @AlexeyZimarev 也许这种与统计相关的东西应该在一个单独的有界上下文中?在这种情况下,我可以使用更简单的架构(即事务脚本)来管理赞成票和查看次数。
  • 如果不能看到您的域是什么,就很难说什么。如果您接受 SO,则赞成票是问题和答案的重要属性。你有什么——我不知道。如果您觉得将它们作为聚合的一部分很尴尬,可能应该将它们取出。

标签: repository domain-driven-design aggregateroot


【解决方案1】:

在查询方面,观看次数、点赞数之类的东西需要 被持久化

不一定。 CQRS 未指定

  • 读取模型是否应在自己的数据库中实现
  • 如何更新读取模型

最简单的 CQRS 实现是查询端和命令端使用相同的表。读取模型的持久源也可以是基于这些表的 SQL(物化)视图。如果您确实有一个单独的数据库用于读取,则可以通过在命令执行后运行的其他命令处理程序或子处理程序或事件处理程序保持最新。

您可以在此处看到极简主义 - 但完全符合 CQRS - 实现:https://github.com/gregoryyoung/m-r/tree/master/SimpleCQRS

但是存储库是唯一可以触及持久性的类吗? 有界上下文?

不,在 CQRS 上下文中,读取模型外观(也称为读取端存储库)也可以从中读取,并且您的读取模型更新机制会写入它。

另外,我使用的是领域事件,某些领域事件也需要 坚持。我需要一种叫做事件存储的东西,但我只听说过 此类术语出现在事件溯源 (ES) 中,我没有使用 ES。

事件存储是事件溯源系统的主要存储技术。您可以使用它们将一些域事件存储在非 ES 应用程序中,但它们对于任务来说可能是多余的并且过于复杂。这取决于您是否需要它们在交付、一致性、并发/版本控制等方面提供的所有保证。否则,常规的 RDBMS 或 NoSQL 存储可以解决问题。

【讨论】:

  • 我知道读存储和写数据库可以分开,也可以共享同一个数据库。查询端可以在接收到域事件时更新读取存储。但我将读取存储(如果单独)视为重复的数据源。真正的副本仍在写入数据库中。但是查询可以直接管理点赞、点击计数等小事的更新(命令端永远不知道它们)吗?
  • 点赞、点击计数之类的东西应该保存在某个地方,并且应该有人管理它们。但它应该是命令端的工作,在这种情况下,只有存储库可以写入数据库;还是应该是查询方的工作?
  • 不,存储库的唯一目的是保持聚合。它不应该保存查询端的特定数据。读取模型的计算和持久化应该进入一个专用的查询端对象。
  • 你的意思是视图计数可以由查询端直接管理(更新和读取)?
  • 当然,如果查看次数(即总查看次数)是非规范化的查询端数据。
【解决方案2】:

首先,您需要独立考虑对象模型,而不考虑如何将其存储在数据库中。您正在设计一个对象模型。暂时忘掉数据库吧。

您是说您不希望查看计数或赞成票成为聚合根。这意味着您希望将它们与其他一些对象放在一起。这些对象之一是聚合根。

如果不了解您的模型的更多信息,很难说您可以使用更多细节做什么,但基本方法是将聚合根与相应的存储库一起保存。存储库不仅负责存储聚合根,还负责存储整个聚合,遵循关系。

想想另一面,当您使用存储库检索实体时。你得到一个聚合根的实例,但如果你遵循关系,你也会拥有所有其他对象。当你保存一个实体时,所有其他对象也会被保存,这是完全合乎逻辑的。

我不知道您使用的是哪种技术,但您应该编写您的存储库以便它执行此操作。

另外,为什么查询端不允许使用存储库?存储库不仅用于保存数据。它们也用于检索它。您如何在没有存储库的情况下检索对象(即使您不修改它们?)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-09-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-19
    相关资源
    最近更新 更多