Domain driven design 在DDD中具有深层层次结构的聚合根是否合适?

Domain driven design 在DDD中具有深层层次结构的聚合根是否合适?,domain-driven-design,aggregateroot,Domain Driven Design,Aggregateroot,我有一个系统,用户以一种形式回答问题。我有表示这个模型的对象,但我不太确定如何根据DDD组织这些对象 表格(有自己的)章节列表 第->(有自己的)组列表 组->(有自己的问题列表) 问题->(可以有自己的子问题列表)问题 问题->(有自己的答案列表) 答案->(有自己的答案详细信息列表) 答案详细信息->(可能有自己的子详细信息列表)子答案详细信息 每个对象都有15个以上的属性,没有父对象,每个属性都没有意义。根据DDD,我认为表单实体应该是聚合根,所有其他对象都应该是值对象。这意味着我只需要表

我有一个系统,用户以一种形式回答问题。我有表示这个模型的对象,但我不太确定如何根据DDD组织这些对象

  • 表格(有自己的)章节列表
  • 第->(有自己的)组列表
  • 组->(有自己的问题列表)
  • 问题->(可以有自己的子问题列表)问题
  • 问题->(有自己的答案列表)
  • 答案->(有自己的答案详细信息列表)
  • 答案详细信息->(可能有自己的子详细信息列表)子答案详细信息

  • 每个对象都有15个以上的属性,没有父对象,每个属性都没有意义。根据DDD,我认为表单实体应该是聚合根,所有其他对象都应该是值对象。这意味着我只需要表单实体的存储库。在这种情况下,FormRepository将充斥着子对象的各种CRUD方法。就DDD而言,我的推理正确吗?我最终得到的是一个非常广泛的聚合,这样可以吗?我相信这样的表示很容易导致性能问题。

    是的,DDD中的深层层次结构很好

    我最终得到一个非常广泛的集合,这样可以吗如果实际情况如此复杂,并且您的域模型是您所能想到的最好的,那么您最终将得到一个复杂的聚合根

    是的,
    表单
    应该是聚合根

    所有其他对象都应该是值对象-错误,所有其他对象都应该是非聚合根实体(具有Id),而没有存储库来获取它们。值对象没有Id,值对象的相等性仅由其属性值决定,而不是由Id的相等性决定(更多信息)

    在这种情况下,FormRepository将充斥着子对象的各种CRUD方法-不,存储库应该只包含有关聚合根的方法,即
    Get,Save where T:IAggregateRoot
    ,一旦获得聚合根的实例,就可以通过属性和方法进行遍历以获得所需的内容。例如:

    var formId = 23;
    var form = _formRepository.Get(formId);
    var firstGroup = form.Sections.First().Group().First();
    
    或者更好

    var groupIndex = 1;
    var firstGroup = form.GetGroupAt(groupIndex);
    
    在哪里

    public Group GetGroupAt(int groupIndex)
    {
        Sections.First().Group().ElementAt(groupIndex);
    }
    

    我相信这样的表示很容易导致性能问题-如果使用,您将从命令处理程序调用一些
    Form
    domain方法,如果您使用NHibernate进行实体持久化,默认情况下它将使用延迟加载,并且只从DB加载
    Form
    ,然后它将只加载您真正接触的实体,例如
    Sections.First()
    将从DB加载所有部分,但不加载组和其他部分。对于查询,您将创建一个
    表单dto
    (数据传输对象)和其他可能扁平化的dto,以获取所需表单中的数据(这可能不同于您的实体结构,UI可能驱动dto结构)。查看我的关于DDD/CQRS/NHibernate/Repository的信息

    即使答案已被接受,我想我还是可以加上我的2美分:

    深层层次结构(可能)很好,但请记住,聚合背后的想法实际上是为了防止这种情况。我倾向于将实体视为一个整体,大致如下:

    “如果没有AR,该实体是否具有任何含义?”

    由于我没有任何上下文w.r.t.您的模型,我将使用
    订单
    /
    订单行
    。如果没有
    订单
    ,订单行是否有任何意义?我可以自己处理订单行吗?显而易见的答案是“不”

    每个模型都需要根据上下文进行处理。但所有权并不一定意味着遏制

    使用单独的有界上下文时,如果BCs正确,则更容易看到这些内容:)

    在您的情况下,
    答案如果没有它的
    问题
    ,可能没有任何意义。但是一个
    问题
    可能存在于
    问题库
    BC中,并且一个特定的问题可以在你的
    考试
    BC和你的
    注册
    BC中使用。所有这些都是完全虚构的,所以这取决于你的背景


    因此,如果
    问题
    可以是AR,那么
    表单
    AR所拥有的问题可能只是一个值对象,甚至是一个简单的问题ID。

    谢谢你的2美分。我不太明白你的意思:如果问题可以是AR,那么你表格AR中的问题可能只是一个值对象。如何
    问题
    成为AR可以是一个值对象。所有应收账款均应为实体。实际上,在我的例子中,没有所有者,所有对象都没有意义。如果没有表单上下文,就无法访问它们。在我的例子中,节和组除了分组问题没有其他意义。请告诉我您的方法是否与@xhafan的方法不同。你们认为什么东西可以是伏萨,我明白为什么答案可能是没有意义的:)---很抱歉。我的意思是,如果BC-A中的AR在BC-B中使用,那么在BC-B中,您可以只使用相关的AR Id,或者将其建模为值对象。模型将100%取决于您对模型的上下文/理解。所以我不能肯定地说,你所拥有的是不正确的。然而,我过去曾以类似的方式对ARs进行建模,事后看来,我知道这不是100%正确的。如果它起作用,那就好了;如果您遇到问题/重复,您需要再次查看模型。最近阅读了推荐使用小聚合的地方。如果一个巨大的聚合包含数千个项目的子实体集合,则可能会出现性能问题,因为向集合中添加一个项目会获取整个集合(例如,nhibernate是这样工作的)。固定到该集合的链接取决于许多因素。是否会同时修改同一表格?如果答案是肯定的,那么您不应该创建更大的集群聚合。还有,你的使用