您如何为Domain Driven Design构建角色/关系?

时间:2009-03-27 11:43:37

标签: domain-driven-design entity-relationship

如果我有三个实体,Project,ProjectRole和Person,其中Person可以是不同项目的成员并且处于不同的项目角色(例如“项目负责人”或“项目成员”) - 您将如何建模这样的关系?

在数据库中,我目前有以下表格:Project,Person,ProjectRole Project_Person with PersonId& ProjectId为PK,ProjectRoleId为FK关系。

我真的很茫然,因为我提出的所有领域模型似乎都打破了一些“DDD”规则。这个问题有“标准”吗?

我看了一个Streamlined Object Modeling,有一个例子,Project和ProjectMember会是什么样子,但Project中的AddProjectMember()会调用ProjectMember.AddProject()。所以Project有一个ProjectMembers列表,每个ProjectMember都有一个对Project的引用。看起来有点费解我。

更新

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

可以创建和修改ProjectMembershipTypes。这些可以是“项目负责人”,“开发人员”,“外部顾问”或其他不同的东西。

一个人可以在项目中拥有多个角色,这些角色可以在特定日期开始和结束。这种关系由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...
}

ProjectMembershipType:ie。 “项目经理”,“开发人员”,“顾问”

public class ProjectMembershipType : IRoleType
{
    public virtual int ProjectMembershipTypeId { get; set; }
    public virtual string Name { get; set; }
    public virtual string Description { get; set; }

    // etc...
}

5 个答案:

答案 0 :(得分:3)

以下是我将如何处理它:

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; }
}

ProjectMember 类将它们整合在一起。此模型使您可以灵活地将相同的Person分配给具有不同角色的不同项目(例如,他可能是ProjectA上的开发人员,以及ProjectB上的测试人员)。

请不要创建特定于角色的课程 - 已经学到了这一课程。

我创建了一个sample app来证明这一点(它也包括关系):

  1. 运行“ bin \ debug \ RolesRelationshipsSample.exe
  2. 双击库图标以创建实体
  3. 拖放它们以指定适当的关系
  4. 随意玩代码。希望你觉得它很有用。

答案 1 :(得分:1)

您正在建模多对多关系:一个项目可以让很多人参与其中,一个人可以处理多个项目。

您将关系建模为项目角色,除了用作来自Person&lt; - &gt;的双向链接之外。 Project,还记录RoleType以及在该Project上填充该RoleType的Person的开始/结束。 (请注意英语是如何工作的“那个”代表数据库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 = ?

或者我们可以从另一个方向跟随它,来自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 c.project_id = ?

理想情况下,我们希望能够在C#代码中执行相同的操作。所以,是的,我们希望一个Person有一个列表,Project需要一个列表,一个ProjectRole引用一个Person和一个Project。

是的,Project::addPerson( Person& )应该是Project::addProjectRole( ProjectRole& ),除非我们认为Project::addPerson( Person& )是表单的便捷方法:

void Project::addPerson( Person& p ) {
  this.addProjectRole( new ProjectRole( p, &this, RoleType::UNASSIGNED ) ;
}

ProjectRole没有列表,它具有对Person的引用和对Project的引用。它还有一个开始日期,一个结束日期和一个RoleType(它是一个枚举,或者是一个模仿枚举值的类实例) - 也就是说,每个枚举类型只有一个对象,它是无国籍,不可改变和幂等,因此在许多ProjectRoles中可以共享。)

现在这并不意味着从数据库中检索Person应该导致整个数据库在代码中的对象图中被确定;只在使用时检索的惰性代理可以从中拯救我们。然后,如果我们目前只关注Person,而不是他的角色(和项目,我们可以只检索Person。(例如,NHibernate,我认为这或多或少是无缝的。)

基本上,我认为:

1)这是表示多对多关系的标准方式; 2)关系的标准是有额外的数据(什么时候,什么样的) 和; 3)你几乎得到了正确的想法,并且在这里获得反馈是正确认真的。

答案 2 :(得分:0)

您是否混淆角色的“描述”与一个人在项目中的角色?添加“RoleDescription”概念(可以说是“角色类”)和“RoleInstance”对象引用项目中的实际人员可能有所帮助。

答案 3 :(得分:0)

您所拥有的是与其他数据(角色)的多对多关系。我们有一个类似的结构,除了在我们的情况下,一个人可能在项目中有多个角色,所以我在同样的问题上挣扎。一种解决方案是创建一个扩展Person的ProjectPerson类并添加role属性:

public class ProjectPerson : Person
{
    public string Role { get; set; }
}

您的Project类现在有一个ProjectPerson集合,但Person类有一个Project集合,因为扩展Project类以添加角色没有意义。您将不得不做一些额外的工作(在ProjectPerson集合中查找Person)从Person的角度查找项目中的角色。

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

在选择解决方案时,考虑数据访问策略在支持模型方面的效果非常重要。您希望避免加载集合需要一次或多次访问集合中每个对象的数据库的情况。

答案 4 :(得分:0)

似乎有两个主要实体 - 项目和项目成员。 项目成员具有“成员角色”和“成员名称”属性。这些属性中的任何一个都可以属于域,即为了方便和用于搜索而可以在查找表中维护的一组值。假设某人需要有关执行特定角色/工作的所有项目成员的信息。

请注意。查找表可以添加条目,但通常不会更改条目的值。从查找表中选择一个值后,它将被视为拥有表的永久固定 - 在本例中为Project Member表。

除了上述情况下的查找表之外,我不希望在任何业务中看到'Person'实体或表。人力资源部门将保留一份员工清单,其中包含工资单等所需的特定信息,但企业需要了解的人员基本没有根据。 NB找到业务流程以识别实体 - 不要弥补。