您的问题缺少一些上下文,例如导致此事件的用户场景是什么以及您从什么状态开始?如果您正在为此案例编写 BDD 测试,它们会是什么样子?了解这一点将有助于回答您的问题。
如何解决将书与作者关联的问题取决于领域。首先,我们假设您的域具有 Author 聚合和 Book 聚合是有意义的,例如,如果我正在编写图书馆系统,我怀疑我是否会有作者聚合,因为我不关心一个没有他/她的书的作者,我关心的是书。
至于缺少 getter,值得一提的是,聚合根没有 getter,因为偏爱告诉-不问的 OOP 风格。但是,您可以告诉一个 AR 做某事,然后在需要时将某事告诉另一个 AR。重要的部分是 AR 会告诉其他人关于它自己的信息,而不是在你问它的地方编写代码然后传递它。
最后,我要问一下,为什么你加书的时候没有作者ID?那你怎么知道作者是谁?我假设您可以执行以下操作(我的代码假设您使用流畅的界面来创建 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 将有作者的 id。
最后一个有缺点,它创建了一个必须通过多个聚合根执行的命令。我会尽可能地弄清楚为什么第一个例子不适合你。
此外,我不能过分强调您正在寻找的实现是如何由您的特定域上下文决定的。