实体框架复杂类型与创建新实体

.net .net-4.0 c# 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实体平滑景观的一个凸起。您的项目中的那些可能没有资格从您的实体基类继承,因此无法通过处理您的实体的方法进行处理。

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

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

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

更进一步,您会遇到需要某种方式通过任何实体并执行操作的情况。也许您想要在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结尾?现在你需要花点时间找出这个特殊情况,这个系统可以在其他任何地方轻松使用。

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




许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因
许可下: CC-BY-SA with attribution
不隶属于 Stack Overflow
这个KB合法吗? 是的,了解原因