Domain driven design 什么属于聚合根

Domain driven design 什么属于聚合根,domain-driven-design,aggregate,root,entities,Domain Driven Design,Aggregate,Root,Entities,这是一个实用的领域驱动设计问题: 从概念上讲,我认为我得到了聚合根,直到我定义了一个 我有一个雇员实体,它以聚合根的形式出现。在企业中,一些员工可能会记录与工作相关的违规行为: 员工------*违规行为 由于并非所有员工都受此影响,我认为违规行为不会成为员工总数的一部分,对吗 所以,当我想与员工及其相关违规行为打交道时,这是由某个服务进行的两个独立的存储库交互吗 最后,当我添加一个冲突时,该方法是否在Employee实体上? 谢谢你的帮助 在做了更多的研究之后,我想我找到了问题的答案 保罗·斯

这是一个实用的领域驱动设计问题:

从概念上讲,我认为我得到了聚合根,直到我定义了一个

我有一个雇员实体,它以聚合根的形式出现。在企业中,一些员工可能会记录与工作相关的违规行为:

员工------*违规行为

由于并非所有员工都受此影响,我认为违规行为不会成为员工总数的一部分,对吗

所以,当我想与员工及其相关违规行为打交道时,这是由某个服务进行的两个独立的存储库交互吗

最后,当我添加一个冲突时,该方法是否在Employee实体上?
谢谢你的帮助

在做了更多的研究之后,我想我找到了问题的答案

保罗·斯托维尔(Paul Stovell)在网上对一个类似问题的回答略作修改。用“客户”代替“员工”,用“订单”代替“违规”,你就明白了

只是因为客户参考了订单 不一定意味着订单会下降 在客户聚合根目录中。 客户的地址可能是,但是 订单可以是独立的(例如 例如,您可能有一个服务 处理所有新订单,无论是谁 客户是,我得走了 客户->订单在中没有意义 这种情况下)

从域的角度来看,您可以 甚至质疑这些数据的有效性 参考资料(客户已参考 订单清单)。你多久去一次 实际上需要所有的订单 顾客在某些系统中,它使 有道理,但在其他情况下,只有一个客户 可能会下很多订单。机会是 您希望在两个月之间为客户下订单 日期范围,或客户的订单 尚未处理的,或订单 没有支付的,等等。 您将需要所有 其中大多数可能比较少见。 然而,更有可能的是 在处理订单时,您将 需要客户信息。所以在 代码,
Order.Customer.Name
很有用, 但是
Customer.Orders[0].LineItem.SKU
- 可能没那么有用。当然 那完全取决于你的生意 域名

换句话说,更新客户与更新订单无关。在我的案例中,订单或违规行为可以独立于客户/员工处理

如果违规有详细信息行,则违规和违规行将成为同一聚合的一部分,因为更改违规行可能会影响违规

编辑**
在我的领域里,问题在于违规行为没有任何行为。它们基本上是所发生事件的记录。我还不确定这会有什么影响。

我想知道结论会是什么

“违规”将成为根实体。“违规”将由“员工”根实体引用。ie违规存储库员工存储库

但是,您对将违规行为作为根实体感到困惑,因为它没有行为


但“行为”是否是根实体资格的标准?我不这么认为。

埃里克·埃文在他的书中说

聚合是一组相关对象,我们将其视为一个单元,用于数据更改

这里有两个要点:

  • 这些对象应视为一个“单元”
  • 为了“数据变更”的目的
  • 我相信在您的场景中,员工和违规不一定是一个单元,而在Order和OrderItem的示例中,它们是单个单元的一部分

    在对聚集边界建模时,另一件很重要的事情是聚合中是否有任何不变量。不变量是应该在“整体”聚合中有效的业务规则。例如,对于Order和OrderItem示例,您可能有一个不变量,表示订单的总成本应小于预定义的金额。在这种情况下,只要您想将OrderItem添加到订单中,就应该强制执行此不变量以确保您的订单有效。然而,在您的问题中,我看不到您的实体之间有任何不变量:Employee和Violation

    简而言之:

    我认为员工和违规行为分别属于两个单独的集合。这些实体中的每一个都是它们自己的聚合根。因此,您需要两个存储库:EmployeeRepository和ViolationRepository

    我也相信你应该有一个从违规到员工的单向关联。这样,每个违例对象都知道它属于谁。但是,如果您想获取特定员工的所有违规列表,则可以询问ViolationRepository:

    var list = repository.FindAllViolationsByEmployee(someEmployee);
    

    在这一点上,我大体上同意莫斯的看法。但是,请记住业务角度中的交易概念。因此,我实际上把“为了数据更改的目的”理解为“为了事务的目的”

    存储库是域模型的视图。在域环境中,这些“视图”实际上支持或表示业务功能或功能—事务。例如,员工可能有一个或多个违规行为,如果是,则是某个时间点内交易的各个方面。考虑你的用例。 场景:“员工做出违反工作场所的行为。”这是发生的一种业务事件(即事务,或更大的、可能是分布式事务的一部分)。受根影响的域对象实际上可以从多个角度看到,这就是为什么它令人困惑的原因。但是要记住的是行为,因为它与业务事务有关,因为您希望您的业务流程尽可能准确地模拟现实世界。就关系而言,就像在关系数据库中一样,您的概念域模型实际上应该已经指出了这一点(即关联性),这通常可以从任意方向读取:

    Customer { /*...*/ }
    
    Employee { /*...*/ }
    
    Repository<T> : IRepository<T>
                  , IEnumerable<T>
                  //, IQueryable<T>, IQueryProvider //optional
    
    { /**/ }
    
    BusinessController {
     Repository<Customer>  Customers { get{ /*...*/ }} //aggregate root
     Repository<Order> Orders { get{ /*...*/ }} // aggregate root
    }