【发布时间】:2016-12-05 09:21:24
【问题描述】:
在领域驱动设计的背景下:
我的域是关于会议和邀请发送的。
一个例子:
用户可以创建一个名为“MyMeeting”的会议,并且他可以通过一些专门的“邀请”来邀请他选择的用户。
我阅读了 Vaughn Vernon 的书 (IDDD),并得出结论,Meeting 和 Invitation 之间不存在不变量。
所以,我开始创建两个不同的聚合根:
-
Meeting(身份证、姓名等) -
Invitation(meetingId,发生在,接收者(目标用户))
我意识到可能会同时发送多个邀请。
所以我想在InvitationRepository 中创建一个特殊查询,旨在一次保存所有邀请:
void addAll(List<Invitation> invitations)
问题在于它引入了与 Invitation 聚合结构的不一致。
说明:
该结构涉及每个Invitation 拥有自己的关联meetingId。
而addAll 旨在添加多个关于同一MeetingId 的邀请;换句话说:每个邀请都通用。
因此,如果我想避免多个数据库查询,由于当前的结构,这种实现会很丑:
void addAll(List<Invitation> invitations) {
//meetingId supposed to be the same across those invitations,
//an ugly way to retrieve it would be :
MeetingId meetingId = invitations.get(0).getMeetingId();
Date occurredOn = invitations.get(0).getOccurredOn();
List<User> receivers = new ArrayList();
for(invitation: Invitations) {
receivers.add(invitation.getReceiver());
}
//then perform the query saving all invitations at once
//=> one invitation for each receiver
}
处理一次保存多个Invitations的情况有什么好的方法?
是否应该更改域结构?
我想到了InvitationRepository中的那些签名:
void add(List<Invitation> invitations)
void addAll(List<Invitation> invitations, MeetingId meetingId, DateTime: occurredOn)
或者甚至使用名为 Invitations 的包装器:
class Invitations { //note the plurality
MeetingId meetingId;
DateTime occurredOn;
List<Invitation> invitations;
//........
}
=> void addAll(Invitations invitations)
将嵌套邀请(聚合根)保存在同一个数据库查询中。
这样,在addAll 实现的情况下,我不会从invitations itself 中选择meetingId 和occurredOn,这会导致一种DRY 违规但保持整体不那么丑陋。
你怎么看?
【问题讨论】:
-
您能演示一下您的 sn-p 如何启用单个查询来提交所有邀请吗?伪代码就够了
-
我正在使用 Neo4J,并且在 Neo4j 中,有一些很好的关键字用于 Cypher 查询,旨在遍历一些数组(在本例中为邀请列表),整个查询过程完全相同。 (类似于我们可以用 PL/SQL 做的事情)
-
如果你给我一个例子,我可能会编辑我的答案,以便在封装的邀请列表中使用它
-
是的,实际上它非常微妙,但它与您的解决方案的本质非常相似,我可以确认。目标是适应/保持 DDD 组件的形态。
-
addAll 方法的正确实现是不关心业务规则的。如果邀请是独立的聚合,那么存储库应该这样对待它们。在循环中调用 add 或调用 addAll 之间不应有不同的语义。 List
邀请 = meeting.inviteAll(invitees); repository.addAll(邀请);
标签: java architecture domain-driven-design aggregateroot