【问题标题】:How to update grandchildren in an aggregate root如何更新聚合根中的孙子
【发布时间】:2012-03-02 14:36:42
【问题描述】:

我首先使用 EF 代码,然后延迟加载。

我的问题与如何有效地更新孙集合中的实体有关。首先,我担心这会在数据库中进行很多并不真正需要的调用。但是,如果我的域类不关心持久性,我看不出另一种方法来做到这一点。

这是课程:

  public class Supplier
 {
  public int Id {get;set;}
  //...Supplier properties

  public virtual ICollection<Contract> Contracts {get;set;} 

  //supplier methods   
 }

 public class Contract
 {
  public int id {get;set;}
  public int SupplierId{get;set;}
  //---Contract properties

  [ForeignKey("SupplierId")]
  public virtual Supplier Supplier {get;set;}
  public virtual ICollection<DeliveryContract> DeliveryContracts {get;set;} 
 }

 public class DeliveryContract
 {
  public int Id {get;set;}
  public bool DeliveryOnMonday{get;set;}
  public bool DeliveryOnTuesday{get;set}
  //...30 different Delivery terms properties

  public Department Department {get;set;}

  public int ContractId {get;set;}
  [ForeignKey("ContractId")
  public virtual Contract Contract {get;set;}
 }

供应商是聚合根。所以我有一个关于供应商的方法是 ChangeDeliveryContract,它对应于现实世界中会发生的情况。

public class Supplier
{
 //properties

 public void ChangeDeliveryContract (DeliveryContract cahangedDc)
 {
   //So from the supplier i have to find the contract to change
   var dcToUpdate = Contracts
                    .SingleOrDefault(c=>c.Id == changedDc.ContractId)
                    .SingleOrDefalut(dc=>dc.Id == changedDc.Id);

   //So... what do i do now? Map all 30 properties from changedDc to DcToUpdate
   //Some business rules is also applied here i.e. there can only be one
   // DeliveryContract between Supplier and Department
 }
}

我使用 MVC,所以程序看起来像: public ActionResult Update (DeliveryContract changedDc, int supplierId)

{
  var Supplier = supplierRepository.GetById(supplierid);
  supplier ChangeDeliveryContract (changedDc);
  supplierRepository.Save();

  //More code...
}

首先,问题在于 ChangeDeliveryContract。我无法让它工作。另外,我觉得像我这样通过集合进行查询可能效率低下。第三,映射30+属性也感觉有点不对。

你们是怎么做的,这里有最佳实践吗。

【问题讨论】:

    标签: entity-framework oop domain-driven-design ef-code-first aggregateroot


    【解决方案1】:

    在应用 DDD 时,聚合根的选择可能会根据模型的各种特性而有所不同,其中包括对子节点数量的考虑等。在这种情况下,虽然 Supplier 是 AR,但这并不意味着 DeliveryContract 可以也不是 AR。虽然看起来 Supplier 是唯一的 AR,并且有关供应商的所有操作都应该源自 Supplier 类,但正如您已经意识到的那样,对于数据库调用而言,这可能会变得不守规矩。 AR 的一个角色是保护不变量,Supplier 类中没有任何内容用于保护不变量,这可能表明 Supplier 不是实现所需业务规则的最合适的 AR .因此,在我看来,在这种情况下,您可以使 DeliveryContract 成为 AR,拥有自己的存储库和应用更改的方法。或者,您可以将 Contract 设为 AR,具体取决于合约是否必须强制执行有关交付合同的任何不变量,以及对每个合同的预期交付合同数量的实际考虑。如果数量非常多,那么在合约类上收集交付合约是不切实际的。总的来说,我会选择更小的 AR,但必须考虑不变量和一致性规则。

    请查看 Vaughn Vernon 撰写的一系列精彩文章,以深入了解该主题:Effective Aggregate Design

    【讨论】:

    • 谢谢。所以我真的阅读了这些文章(阅读了很多),我详细阅读了所有内容,我认为你的建议是有道理的。如果我从一致性的角度考虑这种情况,唯一可以作为聚合根的候选者是合约(即 DeliveryContract 需要一个合约来管理它,如果没有它,它将毫无用处 - 但它具有身份,因此它不是值类型)。那么业务规则必须要么驻留在它自己的层中,要么驻留在对象本身上。
    【解决方案2】:

    好的,这有点令人困惑,我将其归咎于域模型和持久性模型的混合(是的,那些 EF 教程在混淆每个人方面做得很好)。一个不应该影响另一个,这就是为什么你有存储库模式。是的,域不应该关心持久性。

    既然供应商不再了解 EF,让我们看看...如果我理解正确,那么您非常需要重新设计供应商(可能还有子聚合),因为您需要考虑业务规则。

    我很难从该代码中对需求进行逆向工程,但我感觉供应商与不同部门签订了交付合同。当您更改交付合同时,供应商应强制执行在该上下文中有效的业务规则(如果有多个上下文对同一实体有效,这一点很重要)。

    我认为虽然交付合同需要进一步澄清,因为我不敢相信它只是一个只有 30 个属性的愚蠢对象。也许某些业务规则与某些属性相关联?所以,我们需要更多细节。

    另一方面,如果您确实需要映射 30 个属性,因为就是这样,您可以使用 Automapper。

    【讨论】:

    • 感谢您的理解和耐心。是的,我觉得 Excel VBA => Hard Coded SQL => MVC with EF Code First => DDD 的方向相当混乱。我从中学到的例子让我感到困惑。除此之外,供应商和公司就一般条款、发票、折扣等创建一个或两个主要合同。然后每个供应商和部门就交货合同达成一致,其中包括每周每天的交货日期、订单截止日期(因此它很快就是很多属性)。交付条款受其中一份主要合同中的条款约束
    • 业务规则是检查一个供应商和一个部门是否有多个交付合同。还有一些行为是在我未包含的合同更改时向部门发送消息。
    【解决方案3】:

    关于ChangeDeliveryContract中的属性映射,你觉得映射30个属性有点不对劲。映射 30 个属性本身并没有错。如果必须完成,就必须完成。您可以使用 AutoMapper 来简化任务。

    我认为,如果您使用诸如“Supplier.MakeDeliveryOnMonday()”、“Supplier.DontMakeDeliveryOnTuesday()”之类的方法,可以改变代码的“感觉”。您可能可以猜到这些方法的作用(检查业务逻辑并将布尔值设置为 true 或 false)。所以你不必使用像 ChangeDeliveryContract 这样的“大”方法。

    【讨论】:

    • 感谢您的意见。据我所知,这里有几件事需要改变。首先,聚合根的概念比我最初想象的要复杂一些,而且我尝试使用关系强制执行的一些规则在域中混合了一些 DB 思维,应该在实体方法中使用业务逻辑来强制执行。其次,正如您所指出的, ChangeDeliveryContract 并不是一个真正的好方法,您建议的方法更有意义。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-05
    • 1970-01-01
    • 2019-08-28
    • 2016-11-16
    • 1970-01-01
    • 2011-11-13
    • 2018-05-04
    相关资源
    最近更新 更多