我有一个聚合根的类,代表一个Person。一个人必须拥有一个Title(Mr,Mrs,Ms等),这是Person对象的属性。创建人员时,用户必须从下拉列表中选择一个标题,其内容通过另一个页面进行管理。
还可以选择通过只读页面查看此信息,因此通过使用下面的模型,我可以使用ID和名称"手持"并且不必离开并根据标题ID检索标题的ValueName,如果我将TitleId添加为Person而不是Title的属性,我将不得不这样做。
保存人物对象时,标题的ID将作为人员的一部分保留,并存储在人员数据库表中(不会触及包含标题的数据库表)
当填充人员时,存储过程根据标题ID将人员加入到标题中,并返回用于填充人员标题类别的信息。
public class Person : IAggregateRoot, IPerson
{
public string Forename { get;set; }
public string Surname{ get;set; }
public ITitle Title { get;set; }
}
public class Title : IAggregateRoot , ITitle
{
public Guid Id {get;set;}
public string ValueName {get;set;}
}
我的问题是:从DDD的角度来看,可以使用这个类结构并将聚合根对象嵌套在另一个聚合根对象中,因为它是一个"固定列表"或者"查找值"还需要由管理员单独维护吗?
答案 0 :(得分:1)
根据定义,聚合根是聚合的“ROOT”,因此对您的问题的简答题是否定的,聚合根不能嵌套在另一个聚合根中。
请记住,聚合根完全取决于上下文。因此,在管理“人物”的上下文中,标题只是一个实体或价值对象。在管理“标题”的上下文中,标题可以是聚合根。如果是这种情况,则应该有两个单独的“标题”类,每个类对应一个上下文。这是一种变更管理策略,因此在一个上下文中进行的更改不会影响其他上下文。
这是一个可能有助于阐明这个问题的例子。请原谅这些名称,因为需要更多关于您的域名的知识来制作更有意义的名称,所以我将为此示例的目的做出一些假设:
雇用某人的背景
public class Person : IAggregateRoot, IPerson
{
public string Forename { get;set; }
public string Surname{ get;set; }
public Title Title { get;set; }
public DateTime? HireDate { get; set; }
public void Hire(Title granted, IPersonRepository repository)
{
Title = granted; //Grant the new hire this title that we have at our company
HireDate = DateTime.Now;
repository.Save(this);
}
}
public struct Title /* I like to make my value objects structs */
{
public Title (Guid id, string value)
{
Id = id;
Value = value;
}
public Guid Id { get; private set; }
public string FullTitle{ get; private set; } /* This would be the prefix + value + level when loaded from the repository because, in this context, we don't have any need for that level of separation. */
}
创建具有不同级别的新标题的上下文
public class Title : IAggregateRoot, ITitle
{
public string Prefix { get; set; }
public string Value { get; set; }
public int Level { get; private set; }
public void Create(int levelsAvailable, ITitleRepository repository)
{
for (int i = 1; i <= levelsAvailable; i++)
{
Title title = new Title(Prefix, Value) { Level = i };
repository.Save(title);
}
}
}
public class Person : IEntityObject, IPerson
{
public ITitle Title { get;set; }
public string Name { get; set; }
}
为了阐明变更管理策略的原因,请考虑业务是否回来并说每个新员工都要获得90天的试用期权,并且试用期权被定义为1级职称。使用上面的策略,只需要更改一个上下文,这可以消除其他上下文中任何可能的未知故障。
希望这有帮助!
答案 1 :(得分:0)
不,嵌套聚合根也不行。聚合可以包含多个实体,或引用(通过id)到另一个聚合,但它不能封装聚合。
我也会说&#34; Title&#34;不是实体的合适候选人(汇总或其他)。它应该被视为一个&#34;值对象&#34;,实际上 - 它应该只是一个字符串。您可能有一个单独的标题查找表,但这并不意味着您应该从Person对象引用该表。
将标题查找表的维护过程与人员的标题分配分开。选择标题后,将字符串复制到person对象。非规范化是使用值对象的方式。