Domain driven design 您如何在考虑领域驱动设计的情况下为角色/关系建模?

Domain driven design 您如何在考虑领域驱动设计的情况下为角色/关系建模?,domain-driven-design,entity-relationship,Domain Driven Design,Entity Relationship,如果我有三个实体,项目、项目角色和个人,其中一个人可以是不同项目的成员,也可以担任不同的项目角色(如“项目负责人”或“项目成员”)—您将如何建立这种关系 在数据库中,我当前有以下表格:Project、Person、ProjectRole Project_Person,其中PersonId和ProjectId为PK,ProjectRoleId为FK关系 我在这里真的很困惑,因为我提出的所有领域模型似乎都违反了一些“DDD”规则。这个问题有什么“标准”吗 我看了一个流线型对象建模的例子,这里有一个项

如果我有三个实体,项目、项目角色和个人,其中一个人可以是不同项目的成员,也可以担任不同的项目角色(如“项目负责人”或“项目成员”)—您将如何建立这种关系

在数据库中,我当前有以下表格:Project、Person、ProjectRole Project_Person,其中PersonId和ProjectId为PK,ProjectRoleId为FK关系

我在这里真的很困惑,因为我提出的所有领域模型似乎都违反了一些“DDD”规则。这个问题有什么“标准”吗

我看了一个流线型对象建模的例子,这里有一个项目和ProjectMember的样子,但Project中的AddProjectMember()会调用ProjectMember.AddProject()。所以Project有一个ProjectMember列表,作为回报,每个ProjectMember都有一个对项目的引用。我觉得有点复杂

更新

在阅读了更多关于这个主题的内容后,我将尝试以下内容:在我的领域中,存在不同的角色,或者更好的模型关系,它们属于某种角色类型。例如,ProjectMember是一个独特的角色,它告诉我们一个人在项目中所扮演的关系。它包含一个ProjectMembershipType,它告诉我们有关它将扮演的角色的更多信息。我确实知道,人们必须在项目中扮演角色,所以我将对这种关系进行建模

可以创建和修改ProjectMembershipType。这些人可以是“项目负责人”、“开发人员”、“外部顾问”或其他人

一个人在一个项目中可以有许多角色,这些角色可以在某个日期开始和结束。此类关系由ProjectMember类建模

public class ProjectMember : IRole
{
    public virtual int ProjectMemberId { get; set; }
    public virtual ProjectMembershipType ProjectMembershipType { get; set; }

    public virtual Person Person { get; set; }
    public virtual Project Project { get; set; }
    public virtual DateTime From { get; set; }
    public virtual DateTime Thru { get; set; }
    // etc...
}
项目成员类型:即“项目经理”、“开发人员”、“顾问”


你是不是混淆了角色的“描述”和一个人在项目中的角色?添加“RoleDescription”概念(可以说是“role类”)和“RoleInstance”对象(指项目中的实际人员)可能会有所帮助。

您拥有的是与其他数据的多对多关系,即角色。我们有一个类似的结构,除了在我们的案例中,一个人可能在一个项目中扮演多个角色,所以我很难回答同样的问题。一种解决方案是创建一个ProjectPerson类,该类扩展Person并添加role属性:

public class ProjectPerson : Person
{
    public string Role { get; set; }
}
您的Project类现在有一个ProjectPerson集合,但Person类有一个Project集合,因为扩展Project类以添加角色是没有意义的。您必须做一些额外的工作(在ProjectPerson集合中查找此人)才能从此人的角度找到项目中的角色

第二种解决方案是处理与其他数据的多对多关系的标准方法。创建一个ProjectRole类,并将其建模为Project和Person两个一对多关系的多方面。也就是说,Project和Person都有一个ProjectRole集合


重要的是考虑您的数据访问策略在选择解决方案时将如何支持模型。您希望避免加载集合需要对集合中的每个对象进行一次或多次数据库访问的情况。

以下是我的处理方法:

class Person
{
  string Name { get; set; }
  IList<Role> Roles { get; private set; }
}

class Role
{
  string Name { get; set; }
  string Description { get; set; }
  IList<Person> Members { get; private set; }
}

class Project
{
  string Name { get; set; }
  string Description { get; set; }
  IList<ProjectMember> Members { get; private set; }
}

class ProjectMember
{
  Project Project { get; private set; }
  Person Person { get; set; }
  Role Role { get; set; }
}
班级人员
{
字符串名称{get;set;}
IList角色{get;private set;}
}
阶级角色
{
字符串名称{get;set;}
字符串说明{get;set;}
IList成员{get;private set;}
}
班级项目
{
字符串名称{get;set;}
字符串说明{get;set;}
IList成员{get;private set;}
}
类项目成员
{
项目{get;private set;}
Person{get;set;}
角色{get;set;}
}
ProjectMember类将它们集合在一起。此模型使您能够灵活地将同一个人分配给具有不同角色的不同项目(例如,他可能是ProjectA的开发人员,而ProjectB的测试人员)

请不要创建特定角色的课程-该课程已经学习

我创建了一个示例来演示这一点(它还包括关系):

  • 运行“bin\debug\rolesrelationshipsample.exe”
  • 双击库图标以创建实体
  • 拖放它们以指定适当的关系

  • 请随意使用代码。希望您觉得它有用。

    您正在建模一个多对多关系:一个项目可以有许多人参与,一个人可以参与多个项目

    您将关系建模为一个项目角色,该角色除了充当Person Project的双向链接外,还记录一个角色类型以及该角色类型在该项目中填充该角色类型的开始/结束。(注意英文的“that”代表数据库FK,或者在代码中代表指针/引用?)

    由于这些FK,我们可以在数据库中按照从Person到Project Role到Project的图表进行操作:

    select a.person_id, b.project_role_id, c.project_id
    from person a join project_role b on (a.id = b.person_id)
    join project c on (b.project_id = c.id)
    where a.person_id = ?
    
    或者我们可以从另一个方向,从项目:

    select a.person_id, b.project_role_id, c.project_id
    from person a join project_role b on (a.id = b.person_id)
    join project c on (b.project_id = c.id)
    where c.project_id = ?
    
    理想情况下,我们希望能够在C代码中实现同样的功能。是的,我们希望一个人有一个列表,项目有一个列表,项目角色引用一个人和一个项目

    是的,
    Project::addPerson(Person&)
    应该是
    Project::addProjectRole(ProjectRole&)
    ,除非我们决定
    Project::addPerson(Person&)
    是一种方便的形式方法:

    void Project::addPerson( Person& p ) {
      this.addProjectRole( new ProjectRole( p, &this, RoleType::UNASSIGNED ) ;
    }
    
    ProjectRole没有列表,它有一个对个人的引用和对项目的引用。作为值,它还有一个开始日期、结束日期和角色类型(要么是枚举,要么是模仿枚举值的类实例——也就是说,每个枚举类型只有一个对象,它是无状态的、不可变的、幂等的,因此可以在多个ProjectRoles之间共享)

    这并不意味着要找回一个人
    void Project::addPerson( Person& p ) {
      this.addProjectRole( new ProjectRole( p, &this, RoleType::UNASSIGNED ) ;
    }