2010-04-17 245 views

回答

18

完美的例子是一个地址。使用复杂类型的地址比新实体更容易处理。对于复杂类型,您不必处理主键。考虑访问地址有多少种常见类型的实体会有地址(业务单位,人员,地点)。想象一下,填充许多人的地址并需要为每个人设置一个密钥。对于复杂的类型,只需访问它们的内部属性即可完成。这是一个示例的MSDN链接。 http://msdn.microsoft.com/en-us/library/bb738613.aspx

+2

拥有复杂类型而不是普通标量属性有什么好处? – emzero 2010-04-29 01:01:10

+0

@emzero我猜他们很多,这基本上是一个OOD。您可能不想在发送货件时在地址上定义get方法或将地址对象传递给某些其他方法。它也遵循DRY方法。假设你做了一个ToString()覆盖,你只需要为所有具有Address的类执行一次。 – 2012-04-13 15:07:08

+0

这难道不会让所有不同的表的所有地址都难以执行操作吗?如果我想添加地理位置数据,或者清理所有地址格式等?用这张独立的桌子,这不是很容易吗?或者你可以做一些像 repo.ComplexTypes.ToList() – 2013-03-18 08:52:00

0

基于域驱动设计概念,聚合根可以有一个或多个内部对象作为其部分。在这种情况下,内部对象 - 在Aggregate Root的边界内 - 没有任何KEY。父键将应用于它们或以某种方式如此。您的答案返回到保持聚合根内所有零件的好处,使您的模型更健壮,更简单。

+0

聚合根可能包含具有密钥的实体。他们只属于一个聚合根。 – 2015-03-28 11:18:54

10

这个问题已经出现了一段时间了,但我仍然会添加一个答案,希望随之而来的下一个可怜的哭泣知道他在做什么。

复杂类型不支持延迟加载,至少在EF 4.3中不支持延迟加载。我们以地址情况为例。你有一个有15列的Person表,其中5个包含某些个人的地址信息。它有5万条记录。您为具有复杂类型Address的表创建实体Person。

如果您需要在数据库中的所有个人的名单,你会做

var records = context.Persons; 

其中还包括地址,抽5个* 50K值到你的列表中没有任何理由,并用明显的延迟。你可以选择只加载您在一个匿名类型需要

var records = from p in context.Persons 
       select new { 
       LastName = p.LastName, 
       FirstName = p.FirstName, 
       } 

这对于这种情况下行之有效的值,但是如果你需要使用,也就是说,8个非地址栏一个更全面的列表,你要么需要在匿名类型中添加每一个,或只是与第一个案例一起,并返回加载无用的地址数据。

这是关于匿名类型的事情:虽然它们在单个方法中非常有用,但它们强制您在类或子类的其他地方使用动态变量,这会取消Visual Studio的某些重构工具并让您打开运行时间错误。理想情况下,您希望在您的方法中分发实体,以便这些实体尽可能少地携带行李。这就是为什么懒加载非常重要。

说到上面的例子,地址信息应该真正在它自己的表中,并且有一个完整的实体覆盖它。作为一个附带好处,如果您的客户要求第二个人的地址,您可以通过在Person中添加额外的地址引用将其添加到您的模型中。

如果不像上面的例子,你几乎在每个查询中都需要地址数据,并且真的想在Person表中有这些字段,那么只需将它们添加到Person实体即可。你将不再拥有整洁的地址前缀,但它不完全是失去睡眠的东西。

但是等等,还有更多!

复杂类型是一种特殊情况,是普通EF实体平滑景观中的颠簸。你项目中的那些人可能没有资格从你的实体基类继承,这使得他们不可能通过处理你的实体的方法来处理它们。

假设您有一个名为EntityModel的实体基类,它定义了一个属性ID。这是你的所有实体对象的关键,所以您现在可以创建

class EntityModelComparer<T> : IEqualityComparer<T> where T : EntityModel 

,你可以再从类型T的任何IQueryable的其中T是实体类鲜明的()来过滤重复使用。复合类型不能从EntityModel继承,因为它没有ID属性,但这很好,因为无论如何你都不会使用独特的。

更进一步,您遇到了一种情况,您需要某种方式来通过任何实体并执行操作。也许你想要在UI上动态列出一个实体的属性,并让用户对它们执行查询。所以你构建一个类可以实例化的特定类型,并将它采取了整个事情的护理:

public class GenericModelFilter<T> : where T : EntityModel 

哦,等一下,你的复杂类型的类型EntityModel的不是。现在,您必须将实体继承树复杂化以适应复杂类型或摆脱EntityModel合同并降低可见性。

一起移动,添加,基于用户选择你的类中的方法可以创建,你可以使用LINQ用于过滤任何实体类

Expression<Func<T, bool>> GetPredicate() { ... } 

所以现在你可以做这样的事情的表达式:

personFilter = new GenericModelFilter<Person>(); 
companyFilter = new GenericModelFilter<Company>(); 
addressFilter = new GenericModelFilter<Address>(); //Complex type for Person 

... 

var query = from p in context.Persons.Where(personFilter.GetPredicate()) 
      join c in context.Companies.Where(companyFilter.GetPredicate()) on p.CompanyID = c.ID 
      select p; 

这对所有实体对象都是一样的......除了有特殊需求的地址。你不能像对待公司一样为它加入。你可以从Person导航到它,但是你如何将它应用到它上面,最后还是Person?现在你必须花点时间想出一个简单的系统,这个系统在其他地方很容易运行。

该模式在项目的整个生命周期中都会重复出现。我是否根据经验说话?我希望我没有。复杂的类型会阻止你的进步,就像班级背后的一个行为不端的学生一样,不会增加任何内容。自己帮忙,选择实际的实体对象。