3

我正在第一次尝试使用 CQRS 和事件溯源,我有几点我想要一些指导。我想实现一个 SO 风格的声誉系统。这似乎非常适合这种架构。

以 SO 为例。假设一个问题被投票,这会产生一个UpvoteCommand增加问题总分的问题并触发一个QuestionUpvotedEvent

似乎作者的用户聚合应该订阅QuestionUpvotedEvent可以增加信誉分数的。但是我不清楚您如何/何时进行此订阅?在 Greg Youngs 示例中,事件/命令处理连接在 global.asax 中,但这似乎不涉及任何基于聚合 Id 的路由。

似乎每个用户聚合都会订阅每个QuestionUpvotedEvent看起来不正确的信息,为了使这样的方案工作,事件处理程序必须表现出行为来识别该用户是否拥有刚刚被投票的问题。Greg Young 暗示这不应该出现在事件处理程序代码中,它应该只涉及状态更改。

我在这里做错了什么?

非常感谢任何指导。

编辑

我想我们在这里谈论的是问题和用户聚合之间的聚合间通信。我可以看到的一个解决方案是QuestionUpvotedEvent由 a 订阅,ReputationEventHandler然后可以获取相应的用户 AR 并在该对象上调用相应的方法,例如YourQuestionWasUpvoted. 这将反过来生成用户特定的UserQuestionUpvoted事件,从而在未来保留重播能力。这是朝着正确的方向前进吗?

编辑 2

另请参阅此处关于 google 群组的讨论。

4

4 回答 4

6

我的理解是聚合本身不应该订阅事件。领域模型只引发事件。订阅事件的是查询端或其他基础架构组件(例如电子邮件组件)。

域服务旨在处理涉及多个聚合的用例/命令。

在这种情况下我会做什么:

  • VoteUpQuestionCommand被调用。
  • VoteUpQuestionCommand的处理程序调用:

    IQuestionVotingService.VoteUpQuestion(Guid questionId, Guid UserId);

  • 然后这会影响问题和用户聚合,并在两者上调用适当的方法,例如 user.IncrementReputation(int amount) 和 question.VoteUp()。这将引发两个事件;UsersReputationIncreasedEventQuestionUpVotedEvent分别由查询方处理。

于 2011-09-13T09:29:52.317 回答
2

我的经验法则:如果您进行 AR 间通信,请使用 saga。它将事物保持在事务边界内,并使您的链接明确 => 更易于处理/维护。

于 2011-09-12T09:25:42.950 回答
0

用户聚合应该有一个QuestionAuthored事件......在那个事件订阅QuestionUpvotedEvent......同样它应该有一个QuestionDeletedEvent和/或QuestionClosedEvent它在其中进行适当的处​​理,如取消订阅QuestionUpvotedEvent等。

编辑 - 根据评论:

我将实现问题是一个外部事件源并通过网关处理它。反过来,网关负责正确处理任何重放,因此最终结果保持完全相同 - 除了拒绝事件等特殊事件......

于 2011-09-10T07:33:09.137 回答
0

这是旧问题并标记为已回答,但我认为可以添加一些内容。经过几个月的阅读、实践和创建基于 CQRS+ES 的小型框架和应用程序,我认为 CQRS 试图解耦组件的依赖关系和职责。在某些资源中,为每个命令编写您应该在命令处理程序上最多更改一个聚合(您可以在处理程序上加载多个聚合,但其中只有一个可以更改)。因此,在您的情况下,我认为最佳做法是@Tom 回答,您应该使用 saga。如果您的框架不支持 saga(就像我的小框架),您可以创建一些事件处理程序,例如UpdateUserReputationByQuestionVotedEvent. 在那,处理程序创建UpdateUserReputation(Guid user id, int amount)OR UpdateUserReputation(Guid user id, Guid QuestionId, int amount)OR UpdateUserReputation(Guid user id, string description, int amount). 命令发送到处理程序后,处理程序通过用户 ID 加载用户并更新状态和属性。在这种类型的处理中,您可以创建更复杂的场景或工作流程。

于 2016-10-21T08:02:06.600 回答