Domain driven design DDD=>;根聚合中的行为:实例化其他根聚合

Domain driven design DDD=>;根聚合中的行为:实例化其他根聚合,domain-driven-design,aggregateroot,Domain Driven Design,Aggregateroot,我有两个根聚合: -发票 -抱怨 我有一条规定:“如果发票被投诉,我不能删除。” 在我的发票汇总删除行为中,我想检查是否存在如下投诉: Complaint complaint = ComplaintRepository.findByInvoiceId(invoiceId); if(complaint.isOpened) { throw new Exception("Open Complain..."); } else{ ... } 我和我的同事在这一点上意见不一致。 他们对我说,我不能在我的

我有两个根聚合: -发票 -抱怨

我有一条规定:“如果发票被投诉,我不能删除。”

在我的发票汇总删除行为中,我想检查是否存在如下投诉:

Complaint complaint = ComplaintRepository.findByInvoiceId(invoiceId);

if(complaint.isOpened) {
throw new Exception("Open Complain...");
}
else{
...
}
我和我的同事在这一点上意见不一致。 他们对我说,我不能在我的行为中列举抱怨,因为抱怨不是我的全部。 我的意见是,我不能在发票类中有投诉属性,但是: -我可以引用一个带有值对象的对象(他们对此没有问题) -我可以读取/加载实例,因为我没有对其调用行为


你对此有何看法

从技术上讲,您可以执行您的建议:从某个角度来看,如果您通过构造函数注入或方法注入将ComplaintRepository接口注入到发票中,那么发票将取决于存储库和投诉的合同,这是非常允许的


当您说您不能保留对投诉的引用时,您是对的,但是您可以在需要运行操作时将DDD工件(例如工厂/存储库/实体)注入到操作中

然而,您必须问自己的主要一点是:您真的想要两个不同聚合之间的耦合级别吗?在这一点上,他们是如此的结合在一起,他们几乎不能没有一个和另一个操作

考虑到所有这些,您可能会遇到这样的情况:投诉可能只是发票汇总的一部分(尽管您的发票汇总可能有其他责任,您将开始与“设计小汇总”目标斗争)。如果你仔细想想,这就是不变量“如果有投诉,我不能删除发票”的建议

如果无论如何,将投诉作为发票总额的一部分建模是不现实的,那么您还有一些其他选择:

  • 使这些聚合最终保持一致:不要尝试在“一次性”中删除发票,而是在一次操作中将其标记为标记为要删除。此操作在消息传递机制中触发某种域事件。然后,此事件“InvoiceFlaggedForDelete”将检查发票上的投诉。如果你没有抱怨,你就删除它。如果您有投诉,请回滚删除标志

  • 将删除过程置于域服务中。这样,域服务将协调检查投诉和在适当时删除发票的工作。这种方法的缺点是,您的发票实体将不太明确其规则,但DDD方面,这有时是一种可接受的方法


从技术上讲,您可以执行您的建议:从某个角度来看,如果您通过构造函数注入或方法注入将ComplaintRepository接口注入到发票中,那么您的发票取决于存储库和投诉的合同,这几乎是允许的


当您说您不能保留对投诉的引用时,您是对的,但是您可以在需要运行操作时将DDD工件(例如工厂/存储库/实体)注入到操作中

然而,您必须问自己的主要一点是:您真的想要两个不同聚合之间的耦合级别吗?在这一点上,他们是如此的结合在一起,他们几乎不能没有一个和另一个操作

考虑到所有这些,您可能会遇到这样的情况:投诉可能只是发票汇总的一部分(尽管您的发票汇总可能有其他责任,您将开始与“设计小汇总”目标斗争)。如果你仔细想想,这就是不变量“如果有投诉,我不能删除发票”的建议

如果无论如何,将投诉作为发票总额的一部分建模是不现实的,那么您还有一些其他选择:

  • 使这些聚合最终保持一致:不要尝试在“一次性”中删除发票,而是在一次操作中将其标记为标记为要删除。此操作在消息传递机制中触发某种域事件。然后,此事件“InvoiceFlaggedForDelete”将检查发票上的投诉。如果你没有抱怨,你就删除它。如果您有投诉,请回滚删除标志

  • 将删除过程置于域服务中。这样,域服务将协调检查投诉和在适当时删除发票的工作。这种方法的缺点是,您的发票实体将不太明确其规则,但DDD方面,这有时是一种可接受的方法

    • 此声明:

      我有两个根聚合:-发票-投诉`

      还有这个

      我有一条规定:“如果有人投诉发票,我就不能删除。”

      是互斥的,如果您遵循的规则是数据库事务不大于一个聚合(并且您应该尝试遵循它,这是一个好规则)

      聚合是事务边界,这意味着聚合内部发生的事情与将来在同一聚合中发生的事情强烈一致(不变量将保持不变,无论发生什么,聚合始终处于有效状态)

      但是,不同聚合实例之间发生的事情最终是一致的,这意味着没有更高级别的协调,任何东西都无法阻止系统(由多个聚合组成)进入无效状态。聚合仅对其拥有的数据负责

      像您这样的代码:

      Complaint complaint = ComplaintRepository.findByInvoiceId(invoiceId);
      //    
      // at this time a new complain could be added!!!
      //
      if(complaint.isOpened) {
          throw new Exception("Open Complain...");
      }
      else{
         invoiceRepository.delete(invoiceId);// and this would delete the invoice although there is a complain on this invoice!!!
      }
      
      将不遵守业务规则
      如果对发票进行投诉,我无法删除该发票
      ,除非该发票包装在一个大于一个的聚合中