准备View Model时如何“加入”两个聚合根?

时间:2011-02-18 18:43:06

标签: cqrs event-sourcing

假设BookAuthor是我模型中的聚合根。

在阅读模型中,我有一个表AuthorsAndBooks,它是由Book.AuthorId加入的作者和书籍列表

触发BookAdded事件后,我希望收到Author个数据以创建新的AuthorsAndBooks行。

由于Book是聚合根,因此Author事件中不包含BookAdded的相关信息。而且我不能包含它,因为Author root没有getter(根据所有关于CQRS和Event Sourcing的示例和帖子的指南)。

通常我会在这个问题上收到两种答案:

  1. 使用事件处理程序中所需的所有数据丰富域名活动。但正如我所说,我不能为Aggregates Roots做这件事。
  2. 使用“查看模型”中的可用数据。即从View Model加载Author并使用它来构建AuthorsAndBooks行。
  3. 最后一个在并发方面存在一些问题。在BookAdded事件处理时,视图模型中无法使用作者数据。

    您使用什么方法来解决这个问题?谢谢。

5 个答案:

答案 0 :(得分:3)

作为一般建议,让事件处理程序是幂等的,并确保您可以处理乱序消息处理(通过重新排队或构建机制来填充缺失的数据)。 另一方面,请问为什么作者和书籍是如此绝望的集合根源。也许你应该在添加一本书时从作者那里复制(f *是“添加一本书”,这是一个命令)。问题是所有这些组成的例子。下降到现实世界,我怀疑你的问题是否存在。

答案 1 :(得分:3)

您的问题缺少一些上下文,例如导致此事件的用户场景是什么以及您从哪个州开始?如果您正在为此案例编写BDD测试,它们会是什么样子?知道这一点对回答你的问题有很大帮助。

如何解决将图书与作者联系起来的问题依赖于域名。首先,我们假设你的域有一个Author的聚合和Book的聚合是有意义的,例如,如果我正在编写一个库系统,我怀疑我会有一个聚合作者,因为我不关心没有他/她的书的作者,我关心的是书籍。

至于缺乏吸气剂,值得一提的是聚合根没有吸气剂,因为偏爱tell-don't-ask样式的OOP。但是,您可以告诉一个AR做某事,然后如果需要,然后告诉另一个AR。部分重要的是AR 告诉其他人关于自己而不是在你询问的地方编写代码然后传递它。

最后,我要问你为什么在添加这本书的时候没有作者的身份证?你怎么会知道作者是谁呢?我假设您可以执行以下操作(我的代码假设您使用流畅的界面来创建AR,但您可以替换工厂,构造函数,无论您使用什么):

CreateNew.Book()
  .ForAuthor(command.AuthorId)
  .WithContent(command.Content);

现在也许情况是你正在和一位全新的作者一起添加一本书。我要么将它作为两个单独的命令处理(这可能对你的域更有意义),或者按照以下方式处理命令:

var author = CreateNew.Author()
  .WithName(command.AuthorName);

var book = CreateNew.Book()
  .ForAuthor(author.Id)
  .WithContent(command.Content);

也许问题是你对聚合根ID没有任何吸引力,我认为这不是必需的或常见的。但是,假设Id封装对您很重要,或者您的BookAdded事件需要有关作者的更多信息而不是Id可以提供的信息,那么您可以执行以下操作:

var author = CreateNew.Author()
  .WithName(command.AuthorName);
var book = author.AddBook(command.Content);

// Adds a new book belonging to this Author
public Book AddBook(BookContent content) {
  var book = CreateNew.Book()
    .ForAuthor(this.Id)
    .WithContent(command.Content);
}

这里我们告诉作者添加一本书,此时它会为书籍创建聚合词根并将其ID传递给书籍。然后我们可以使用具有作者身份的事件BookAddedForAuthor。

最后一个有缺点,它创建了一个必须通过多个聚合根进行操作的命令。我会尽可能地弄清楚为什么第一个例子不适合你。

此外,我无法强调您正在寻找的实施方式取决于您的特定域上下文。

答案 2 :(得分:2)

恕我直言,从作者/书籍事件中填充读取模型,使用重新排序来处理事件失序的情况(视图处理程序在其自身的一致性边界内,并且无论如何都应处理排序/重复数据删除案例)。

答案 3 :(得分:0)

我要问的第一件事是为什么在读模型中存在并发问题。如果客户端在AddBook命令中发送对作者聚合的引用,它从何处获取信息?如果书籍和作者同时创建,那么您的活动可能会丰富。如果我在这里遗漏了一些东西,请告诉我。

答案 4 :(得分:0)

  

最后一个有一些问题   并发性。作者数据可能不是   在View Model中可用   BookAdded事件正在处理中。

“以后处理事件”怎么样?所以你只需将它放在队列的后面,直到这些数据可用(可能有x次尝试的限制和每次尝试之间的x时间)。