entity framework复杂类型与创建新实体

我正在阅读有关Entity Framework 4.0的内容,我想知道为什么要创建复杂类型而不是新实体(表)以及它们之间的关系?

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

这个问题已经存在了一段时间了,但无论如何我都要补充一个答案,希望下一个可怜的呜咽知道他在做什么。

复杂类型不支持延迟加载,至少在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实体平滑景观的颠簸。 项目中的那些可能没有资格从您的实体基类inheritance,因此无法通过处理您的实体的方法将它们放入。

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

 class EntityModelComparer : IEqualityComparer where T : EntityModel 

然后,您可以使用Distinct()从类型为T的任何IQueryable中过滤重复项,其中T是实体类。 复杂类型不能从EntityModelinheritance,因为它没有ID属性,但这很好,因为无论如何你都不会在它上面使用distinct。

在这种情况下,您会遇到需要某种方式通过任何实体并执行操作的情况。 也许您想要在UI上动态列出实体的属性,并让用户对它们执行查询。 因此,您构建了一个类,您可以为特定类型实例化并让它处理整个事情:

 public class GenericModelFilter : where T : EntityModel 

哦等等,你的复杂类型不是EntityModel类型。 现在,您必须使实体inheritance树复杂化以适应复杂类型或删除EntityModel合约并降低可见性。

继续,您向类添加一个基于用户选择的方法可以创建一个表达式,您可以使用linq来过滤任何实体类

 Expression> GetPredicate() { ... } 

所以现在你可以这样做:

 personFilter = new GenericModelFilter(); companyFilter = new GenericModelFilter(); addressFilter = new GenericModelFilter
(); //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结尾? 现在你需要花点时间找出这个特殊情况,以便在其他地方轻松使用。

这种模式在项目的整个生命周期中都会重复出现。 我是否从经验中说话? 我希望我没有。 复杂的类型会阻止你的进步,就像课后的一个行为不端的学生一样,没有添加任何本质的东西。 帮个忙,选择实际的实体对象。

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