如何更新聚合根目录中的孙子孙女

时间:2012-03-02 14:36:43

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

我使用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 +属性也感觉有点不对。

你们是怎么做到的,这里有最好的做法。

3 个答案:

答案 0 :(得分:1)

好吧,这有点令人困惑,我把它归咎于域和持久性模型的混合(是的,那些EF教程已经做了很大的混淆每个人的工作)。一个人不应该影响另一个,这就是你拥有存储库模式的原因。是的,域名不应该关心持久性。

现在Suplier不再了解EF了,让我们看看......如果我理解正确,那么你需要重新设计供应商(也可能是儿童聚合),因为你需要考虑到业务规则。

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

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

作为一方,如果您真的需要映射30个属性,因为它就是这样,您可以使用Automapper。

答案 1 :(得分:1)

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

查看Vaughn Vernon撰写的一系列文章,深入探讨这一主题:Effective Aggregate Design

答案 2 :(得分:1)

关于ChangeDeliveryContract中的属性映射,您觉得映射30个属性有点不对。本身映射30个属性没有任何问题。如果必须这样做,就必须这样做。您可以使用AutoMapper来简化任务。

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