基本综合问题

时间:2011-08-17 17:59:40

标签: c# .net domain-driven-design

是否允许客户端代码引用不是根的聚合中的实体?我有Story(根),Team(实体)和TeamMember(实体)。我想确定AddTeamMember方法是否属于TeamStory

我想我的例子有点误导。我真正的问题是客户端代码可以引用聚合中的非根实体吗?

4 个答案:

答案 0 :(得分:1)

我的意见 - 它不应该。引用属于某个聚合的实体意味着您可以在没有完整聚合上下文的情况下调用该实体上的方法,如果允许,您永远无法确定整个聚合是否有效且一致。

简单示例:

    public class MyAggregateRoot
    {
        protected MyEntity entity;

        public void BuildUpAggregate()
        {
            ValidateSomeRule();
            LoadEntityFromDatabase();
        }

        public MyEntity MyEntity
        {
            get 
            {
                VerifySomeOtherRule();
                return entity; 
            }
        }
    }

正如您所看到的,在通过聚合根构建和检索MyEntity时,我们检查了两个验证规则 - 如果您允许客户端直接引用MyEntity,则聚合可能会在客户端检索实体并执行操作之间及时更改它,所以检查将不再有效,但你不会意识到这一事实。换句话说,您的聚合将不一致且可能无效。

通常,在DDD中有一条强有力的规则,规定聚合中对实体的所有访问都应该通过遍历聚合根来执行 - 这个规则正是为了聚合的一致性。

也就是说,您的客户可以引用的是对实体的投影 - 一种只读副本,其中仅包含显示和决定当前上下文中某个操作是否可用所需的数据。您可以更进一步,将一组实体中的数据聚合到一个投影中,稍微调整一下,这样就可以根据UI的要求进行调整。我发现这种技术对于不允许我的UI决定如何建模业务域非常有用。

答案 1 :(得分:0)

在不知道您的架构应该如何工作的情况下,它听起来应该继续Team而不是Story。假设您从TeamTeam Member有1对多,Team MemberTeam对象的子项,而不是Story

答案 2 :(得分:0)

我不确定“root”或“聚合”规则,但我认为故事不应该知道如何管理团队成员资格。

答案 3 :(得分:0)

团队应该与团队成员“有”关系。故事和团队成员彼此之间没有直接关系。

你的班级应该是这样的:

class team
{
list<TeamMember> teamMembers;
void AddTeamMember(TeamMember member){}
}

团队必须添加团队成员方法的另一个原因是,如果该方法是故事的一部分,那么您必须明确提及要添加成员的团队。

addteamMember(Team T, TeamMember member);

Root应该提供访问非root元素的正确方法(第一级嵌套)。在你的情况下,团队应该有addTeamMember方法,故事应该有一个方法(AddMemberToTeam(team t,teammember m)),它调用指定团队的addTeamMember方法。