使用来自多个聚合根(不同上下文)的数据读取模型

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (35)

我很想知道如何在事件源聚合根的读模型中连接来自多个聚合根的数据。可以试着举一个简单的例子:

如果我有一个名为Cart的聚合根,它支持事件流中的后续事件(括号中的属性 - 请记住这是一个简单的例子):

AddProductToCart(cartId: Int, productId: Int)
RemoveProductFromCart(cartId: Int, productId: Int)
AddUserLicenseToProduct(cartId: Int, productId: Int, userId: Int)
RemoveUserLicenseFromProduct(cartId: Int, productId: Int, userId: Int)
EmptyCart(cartId: Int)

在使用来自此事件流的数据投影读取模型时,这是可以的。我可以举例说明一个看起来像这样的购物车对象:

Cart(cartId: Int, products: List[Product])

Product(productId: Int, userLicenses: List[UserLicense])
UserLicense(userId: Int)

但是如何将来自另一个上下文中的另一个聚合根的数据连接到此购物车投影中。例如,如果我想使用位于另一个上下文中的Product聚合根来扩展读模型。假设我想用productName和productType扩展它。

考虑到我们正在分布式系统中工作,其中产品和购物车将存在于不同的服务/应用程序中。

我想一个解决方案是将数据包含在命令和事件中。但是,如果一个人拥有来自多个聚合根的数据的更大的读取模型,那么这似乎不会很好地扩展。还必须能够核对并重建读取模型。

我想另一种解决方案是将来自其他聚合根的数据复制到其他应用程序/服务/上下文的存储中。例如,将productName和productType数据复制到Cart应用程序所拥有的存储中,但不要将它作为Cart事件流的一部分。然后Cart应用程序必须监听事件(例如ProductCreated,ProductNameChanged)以保持数据更新。我想这可能是一个可行的解决方案。

提问于
用户回答回答于

每个有界的上下文应该松散耦合。我们的两个背景中存在类似的问题。我们发现的解决方案是通过在这些文件中创建上下文之间的所有通信来使用工作流。我们可以通过订阅事件处理程序来同步所需的模式。当我们使用Elixir时,我们使用的库是Commanded,它有自己的Event Bus。

但在分布式系统中,您可以使用Apache Kafka。在一天结束时,我认为更简单的解决方案应该使您的模式尽可能最简洁(它还将帮助您尊重GDPR合规性)并通过事件处理程序通过单独的层管理您的所有通信。

要以“真实”的方式看待这个解决方案,我可以向您推荐一个使用Elixir构建的优秀示例存储库。

https://leanpub.com/buildingconduit/read

用户回答回答于

这个问题还提出了事件驱动的架构,而不仅仅是事件源。我认为你已经涵盖了从事件制作人那里获取相关数据的大多数选项。

另一种选择是事件包含尽可能少的来自相关有界上下文的数据。至少这将是一个标识符。但是,在大多数情况下,某些数据应该非规范化才有意义。例如,将产品描述非规范化为Cart最终Order将会有所帮助,尤其是当我做出选择后有人更改描述时。描述可能会发生变化Blue penRed pen从而彻底改变我打算购买的内容。在这种情况下,ProductShoppingBC 可以由包含一个值对象表示Id与沿Description

如果您现在想要扩充只读数据,我们只能选择从源BC中检索它。这可以使用一些API(Rest / ACL)在读取模型中完成,然后保存数据。为了使其更具容错性,可以选择消息传递/服务总线基础设施来处理附加数据的检索和相关读取模型记录的更新。

扫码关注云+社区

领取腾讯云代金券