嗨我的第一次使用DDD / CQRS。我已经阅读了多种知识来源,我仍然感到困惑,也许有人可以提供帮助:)。
让我们假设我们有产品和客户(可能是不同的有界上下文)的简单情况。 客户可以购买产品,并希望看到他购买的所有产品。
在这种情况下,我意识到我需要一个 UserPurchasesView 视图模型:
现在......问题是我的域名正在生成像 UserPurchasedProduct(userId,productId)这样的事件。我可以用奖品,产品名称或其他东西来丰富一个活动,但不是所有领域。我到了富裕似乎是错误的地步。
在这一点上,我意识到我需要像 ProductDetailsView :
这样的东西此视图由以下事件维护:ProductCreated,ProductRenamed,ProductImageChanged
现在我们有两个选择......
这些解决方案对我来说都不是很完美。我错了,我错过了什么或者只是这样做的方式?谢谢!
答案 0 :(得分:3)
你理解得很好。
因此,您必须在读取模型之间进行耦合以及在UI和各个读取模型之间进行耦合。
CQRS / ES的一个主要优点是可以创建超快速读取模型(视图,如果你喜欢),没有任何连接,完美的缓存,正如我所看到的那样。我个人每次都选择第一种方法,完全数据非规范化。视图非常快,模型非常干净清晰。 这是一个完美的解决方案如果你想优化应用程序的读取方面(我认为你应该)。 通过聆听正确的事件,您可以使这些读取模型与应用程序的其余部分保持同步。
答案 1 :(得分:2)
有第三种选择:
负责UserPurchasesView视图的投影不仅会监听UserPurchasedProduct事件,还会监听ProductCreated,ProductRenamed,ProductImageChanged - 任何影响UserPurchasesView的产品相关事件。现在,除了它负责的读取模型的UserPurchasesView集合之外,它还需要一个私有集合来维护它感兴趣的产品:( {id,name,image,shortDescription,[也许还有其他]因此,当新的购买事件进入时,您可以从某处获得这些产品字段的初始状态。由于您的UserPurchasesView无论如何都需要收听其中一些产品事件,以便在产品发生变化时保持最新状态,这不是额外的工作,并且避免了对其他投影的依赖(ProductDetailsView)。由于最终的一致性,交叉投影依赖性也存在潜在的问题 - 当UserPurchasedProduct事件发生时,如果产品甚至不在产品详细信息视图中,该怎么办?
为了避免任何并发问题,最简单的方法是让每个投影只由一个进程和一个线程管理。这样,只要投影可以跨流顺序接收事件(以便保证在产品购买之前看到产品创建),您就不会在产品存在之前看到购买产生问题。如果为投影引入分片或任何其他多线程,则会变得更复杂。