【问题标题】:What is the best way to fill updated data from one aggregate root to another?将更新数据从一个聚合根填充到另一个聚合根的最佳方法是什么?
【发布时间】:2017-08-03 09:13:01
【问题描述】:

我尝试了解将属性从一个聚合根填充到另一个聚合根的最佳方法。

我有Model Aggregate RootCategory Aggregate RootFilter Aggregate Root

每个Model 都可以有一些Filter 列表,并且可以在Category 之一中。 Category 可以有一个Filter 用于继承Model。当ModelCategory属性更新时,Filter必须从Category继承到Model,当Category中的Filter属性更新时,所有Models都来自那个@ 987654338@ 必须继承新值。所有继承的Filters都无法更新,但可以编辑手动添加的过滤器。

我“发明”的一种方法是使用 Process manager 和包含 Category filterModels list 的状态。

所以我会有这样的行为:

  1. Category ARUpdateCategoryFilter(命令)-> CategoryFilterUpdated(事件)
  2. Model AR AddCategory (命令) -> CategoryAdded (事件), RemoveCategory (命令) -> CategoryRemoved (事件), InheritFilter (命令) -> FilterInherited (事件), RemoveInheritedFilter (命令) -> InheritedFilterRemoved (事件)
  3. Filter AR CreateFilter(命令)-> FilterCreated(事件)
  4. 进程管理器FilterInheritance 拥有correlationIdResolver by categoryId,触发 [CategoryFilterUpdated, CategoryUpdated] 事件

PM 行为是这样的:

current State(filter, models) =>
  if CategoryFilterUpdated(... newFilter ...) =>
    set new State(... newFilter ...) {
      models.forEach(send InheritFilter(model, newFilter))
    }
  if CategoryAdded(.... modelId ...) =>
    set new State(... models.add(modelId) ... ) {
      send InheritFilter(modelId, filter)
    }
  if CategoryRemoved(.... modelId ...) =>
    set new State(... models.remove(modelId) ... ) {
      send RemoveInheritedFilter(modelId, filter)
    }

这是正确的方法吗?还有其他方法吗?

【问题讨论】:

  • 为什么称这段代码为“流程管理器”?它管理什么样的流程,流程什么时候开始,什么时候结束?
  • 这是一些伪代码。它是some ,它侦听事件流并在相关事件(CategoryFilterUpdatedCategoryUpdated)出现时通过发送命令(InheritFilter(model, filter))更改其状态(State(filter, models))。
  • 这不是我的问题。我的问题是你的流程是什么?那里没有进程,只有几个事件处理程序。

标签: domain-driven-design cqrs event-sourcing


【解决方案1】:

请记住,聚合用于在进行状态更改时保护域不变量,而不是用于简单的 CRUD。目前尚不清楚您的域是什么,以及可能会向“模型”发送什么样的命令,其中保护不变量需要知道模型的“过滤器”是什么。

如果命令需要根据聚合的状态进行验证,或者如果该命令会影响将来可能发送到聚合的命令的处理,您只需将命令发送到聚合。目前尚不清楚您是否属于这种情况。模型聚合是否必须根据它拥有的过滤器来验证命令/发出事件?如果不是,则处理此问题的方法是纯粹在读取端进行 - 读取端可以跟踪模型的当前过滤器,并且客户端/进程可以根据需要使用它。因此,您的模型读取投影将只需要监听 CategoryAdded、CategoryFilterUpdated 等来更新模型的读取视图。

如果您确实需要过滤器来验证模型命令或发出适当的事件以响应这些命令,那么您所拥有的似乎是一种选择。但是检查您的业务需求以查看是否可以在模型聚合之外完成过滤等将是有价值的,因为在聚合之间复制命令会增加耦合 - 您在发送 InheritFilter 等命令和客户端发送之间也存在竞争条件需要该过滤器的模型的命令,这似乎是一个可能需要客户端处理以轮询模型以准备好执行命令的问题。

【讨论】:

  • 感谢“聚合用于在进行状态更改时保护域不变量,而不是用于简单的 CRUD”。我认为这是主要的“核心”,这是从 CRUD 模式迈出的难点。
【解决方案2】:

看起来很像您正在执行 CRUD 样式的数据操作操作,而不是采用域方法。

您可能遇到的另一个问题是假设您可以使用 Aggregate 在 UI 上显示信息。聚合原则上没有任何外部可见的属性(除了 ID 没有 getter)。如果他们这样做,他们将不会被很好地封装。您最好在 UI 上使用读取模型。本文可能会让您更好地了解典型 CQRS 应用程序的结构:CQRS + Event Sourcing – A Step by Step Overview

假设您正在寻找使用 DDD 风格的方法,我会先看看您的聚合。我不知道您的域,但从表面上看,它看起来只是 1 个聚合根。不确定它会被称为什么,因为我对您的域一无所知。

例如,我不希望真实用户会说“InheritFilter”之类的话。您可能还希望查看这篇文章,以帮助您了解如何命名您的事件以及您的命令:6 Code Smells with your CQRS Events – and How to Avoid Them

我希望这有助于解决您的一些问题。我个人发现很难理解 DDD、CQRS 和事件溯源。我不得不忘记一堆东西。但正因为如此,我成为了一个更好的开发者。

希望这会有所帮助。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-07-10
    • 1970-01-01
    • 1970-01-01
    • 2015-01-04
    • 2018-08-12
    • 1970-01-01
    • 2017-08-25
    • 2019-08-07
    相关资源
    最近更新 更多