基本综合问题
是否允许客户端代码引用非根聚合中的实体?我有一个Story
(根)、Team
(实体)和TeamMember
(实体)。我试图确定 AddTeamMember
方法是否属于 Team
或 Story
。
我想我的例子有点误导。我真正的问题是客户端代码可以引用聚合中的非根实体吗?
Is client code allowed to reference entities within an aggregate that is not the root? I have a Story
(Root), Team
(Entity) and TeamMember
(Entity). I am trying to decided if the AddTeamMember
method belongs on the Team
or Story
.
I guess my example was a little mis-leading. My real question is can client code reference non-root entities within an aggregate?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我的意见 - 不应该。引用属于某个聚合的实体意味着您可以在没有完整聚合上下文的情况下调用该实体上的方法,如果您允许这样做,您将永远无法确定整个聚合是否有效且一致。
简单的示例:
如您所见,在通过聚合根构建和检索 MyEntity 时,我们检查了两个验证规则 - 如果您允许客户端直接引用 MyEntity,则聚合可能会在客户端检索实体和执行操作之间的时间发生变化它,因此支票将不再有效,但您甚至不会意识到这一事实。换句话说,您的聚合将不一致并且可能无效。
一般来说,在 DDD 中有一条强有力的规则,规定对聚合中的实体的所有访问都应该通过从聚合根开始遍历来执行——这条规则正是为了聚合的一致性。
也就是说,您的客户端可以引用的是实体的投影 - 一种只读副本,其中仅包含显示和决定特定操作在当前上下文中是否可用所需的数据。您可以更进一步,将一组实体中的数据聚合到单个投影中,稍微调整一下,以便根据 UI 的要求进行定制。我发现这种技术非常有用,因为它不允许我的 UI 决定如何对业务领域进行建模。
My opinion - it should not. Having a reference to an entity that belongs to certain aggregate means that you are able to invoke a method on that entity without full aggregate context and if you allow that, you can never be sure if your entire aggregate is valid and consistent.
Simple example:
As you can see, while building and retrieving MyEntity via aggregate root we have two validation rules checked - if you would allow the client to reference MyEntity directly, the aggregate might change in time between client retrieved the entity and performed an operation on it, so the checks would no longer be valid, but you wouldn't event be aware of this fact. In other words, your aggregate would be inconsistent and potentially invalid.
In general, in DDD there's a strong rule that states that all access to entities in aggregate should be performed by traversing from the aggregate root - this rule is exactly for the sake of consistency of aggregates.
That said, what your client can reference is a projection of an entity - a sort of read-only copy that contains only data required for displaying and deciding whether a certain action is available in current context. You can go even further and aggregate the data from a set of entities to a single projection, tune it up a little, so it would be tailored to the requirements of UI. I found this technique quite useful for not allowing my UI to decide how the business domain should be modeled.
在不知道您的架构应该如何工作的情况下,听起来它应该在
Team
而不是Story
上进行。假设您有一个从Team
到Team Member
的一对多关系,并且Team Member
是Team
的子级code> 对象,而不是Story
。Without knowing how your architecture is supposed to work, it sounds like it should go on
Team
instead ofStory
. That's assuming you have a 1 to many fromTeam
toTeam Member
, and thatTeam Member
is a child of theTeam
object, notStory
.我不确定“根”或“聚合”规则,但我认为故事不应该知道如何管理团队成员资格。
I'm not sure about 'root' or 'aggregate' rules but I don't think a Story should know anything about how a Team's membership is managed.
团队应该与团队成员有“有”关系。其中故事和团队成员彼此没有直接关系。
你的类应该如下所示:
团队必须有添加团队成员方法的另一个原因,如果该方法是故事的一部分,那么你必须明确提及你想要在哪个团队中添加成员。
根应该提供正确的方法来访问非根元素(第一层嵌套)。在您的情况下,团队应该有 addTeamMember 方法,而故事应该有一个方法 (AddMemberToTeam(team t, teammember m)) 调用指定团队的 addTeamMember 方法。
Team should have "has a" relationship with Team member. where as story and team member are not directly related to each other.
your class should look like:
another reason why Team must have add team member method, if the method is part of story then you have to explicitly mention in which team you want to add member.
Root should provide proper methods to access non root elements(first level of nesting). In your case Team should have addTeamMember method and story should have a method (AddMemberToTeam(team t, teammember m)) which calls addTeamMember method of specified team.