假设Book
和Author
是我模型中的聚合根。
在阅读模型中,我有一个表AuthorsAndBooks
,它是由Book.AuthorId
加入的作者和书籍列表
触发BookAdded
事件后,我希望收到Author
个数据以创建新的AuthorsAndBooks
行。
由于Book
是聚合根,因此Author
事件中不包含BookAdded
的相关信息。而且我不能包含它,因为Author
root没有getter(根据所有关于CQRS和Event Sourcing的示例和帖子的指南)。
通常我会在这个问题上收到两种答案:
Author
并使用它来构建AuthorsAndBooks
行。最后一个在并发方面存在一些问题。在BookAdded
事件处理时,视图模型中无法使用作者数据。
您使用什么方法来解决这个问题?谢谢。
答案 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时间)。