使用来自其他聚合的数据检查命令的有效性

Dis*_*Stu 6 domain-driven-design aggregate web

我目前正在开发我的第一个更大的 DDD 应用程序。目前它运行得很好,但我们从早期就陷入了一个我无法停止思考的问题:

在我们的一些聚合中,我们保留对另一个聚合根的引用,这对于整个应用程序非常重要(基于它们的 ID,因此没有硬引用 - 删除也是基于事件/最终一致性)。现在,当我们创建新实体“Entity1”时,我们发送一个新的 CreateEntity1Command,其中包含引用的聚合根的 ID。

现在我如何检查这个引用的 ID 是否有效?现在我们通过读取其他聚合来检查它(不修改那里的任何内容) - 但这种方法不知何故感觉很脏。我只想“信任”这些命令,因为无法手动输入 ID,而必须选择 ID。问题是,我们的应用程序是一个 Web 应用程序,信任您在那里获得的用户输入并不真正安全(即使公众无法访问它)。

我是否忽略了这个问题的任何可能的解决方案,或者我应该忽略需要有更好的解决方案的感觉?

Con*_*enu 7

验证另一个引用的聚合是否存在不是聚合的责任。它将打破单一责任原则。当CreateEntity1Command到达聚合时,应该认为另一个引用的聚合处于有效状态,即它存在

在聚合边界之外,这种检查最终是一致的。这意味着,即使它最初通过,之后也可能变得无效(即它是deletedunpublished或任何其他无效的域状态)。您需要确保:

  • 如果引用的聚合尚不存在,则该命令将被拒绝。在使用域服务将命令分派到聚合之前,您可以在负责用例的应用程序服务中执行此检查。

  • 如果引用的聚合随后进入无效状态,则会采取正确的操作。您应该在 Saga/Process 管理器中执行此操作。如果使用CQRS,您订阅相关事件;如果没有,您可以使用cron. 什么是正确的操作,这取决于您的领域,但主要思想是它应该建模为一个过程。

因此,长话短说,聚合的责任不会超出其一致性边界

PS 抵制将服务(无论是否为域)注入聚合(通过构造函数或方法参数)的诱惑。


Kan*_*shk 2

直接聚合到聚合交互是 DDD 中的反模式。聚合 A 不应直接向聚合 B 发送命令或查询。聚合是严格的一致性边界。

我可以想到解决您问题的 2 个解决方案:假设您有 2 个聚合根 (AR) - A 和 B。每个 AR 都有一堆命令处理程序,其中每个命令都会引发 1 个或多个事件。A 中的命令处理程序取决于 B 中的某些数据。

  1. 您可以订阅 B 引发的事件,并在 A 中维护 B 的状态。您只能订阅规定有效性的事件。

  2. 您可以在 A 和 B 之间建立一个完全独立的服务 (S) 进行协调。不要直接将请求发送到 A,而是将请求发送到 S,S 将负责来自 B 的查询(以检查引用 ID 的有效性),然后将请求转发给 A。这有时称为流程管理器 (PM)。

例如,在您创建新实体“Entity1”的情况下,将此请求发送给 PM,其工作是验证请求中的数据是否有效,然后将您的请求路由到负责创建“Entity1”的聚合。向该 PM 发送一个包含引用的聚合根 ID 的新 CreateEntity1Command,该 PM 使用引用的 AR 的 ID 来确保其有效,如果有效,则只有它才会转发您的请求。

有用的链接: http: //microservices.io/patterns/data/saga.html