我使用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 +属性也感觉有点不对。
你们是怎么做到的,这里有最好的做法。
答案 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这样的“大”方法。