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

C# 实体框架复杂类型与创建新实体,c#,.net,entity-framework,.net-4.0,C#,.net,Entity Framework,.net 4.0,我正在阅读EntityFramework4.0,我想知道为什么我应该创建一个复杂的类型,而不是一个新的实体(表)和它们之间的关系?一个完美的例子是地址。对地址使用复杂类型比处理新实体容易得多。对于复杂类型,您不必处理主键。考虑访问一个地址有多少常见类型的实体会有一个地址(业务单位、人员、地点)。想象一下,填充许多人的地址,并需要为每个地址设置一个键。对于复杂类型,您只需访问其类型的内部属性即可。下面是一个示例的MSDN链接 基于域驱动的设计概念,聚合根目录可以有一个或多个内部对象作为其组成部分。

我正在阅读EntityFramework4.0,我想知道为什么我应该创建一个复杂的类型,而不是一个新的实体(表)和它们之间的关系?

一个完美的例子是地址。对地址使用复杂类型比处理新实体容易得多。对于复杂类型,您不必处理主键。考虑访问一个地址有多少常见类型的实体会有一个地址(业务单位、人员、地点)。想象一下,填充许多人的地址,并需要为每个地址设置一个键。对于复杂类型,您只需访问其类型的内部属性即可。下面是一个示例的MSDN链接

基于域驱动的设计概念,聚合根目录可以有一个或多个内部对象作为其组成部分。在这种情况下,聚合根边界内的内部对象没有任何键。父密钥将应用于它们,或者以类似的方式应用于它们。您的答案返回到将所有部分保留在聚合根中的好处,这使您的模型更加健壮和简单。

这个问题已经在这里讨论了一段时间,但我还是要添加一个答案,希望下一个可怜的sob知道他在干什么

复杂类型不支持延迟加载,至少在EF4.3中不支持。让我们以地址情况为例。您有一个包含15列的Person表,其中5列包含特定个人的地址信息。它有5万张唱片。您可以为具有复杂类型地址的表创建实体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实体中即可。你将不再有整洁的地址前缀,但这并不是什么让人失眠的事情

但是等等,还有更多

复杂类型是一种特殊情况,是平坦EF实体平滑地形上的凹凸。项目中的对象可能不符合从实体基类继承的条件,这使得它们无法通过处理实体的方法进行处理

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

class EntityModelComparer<T> : IEqualityComparer<T> where T : EntityModel
class EntityModelComparer:IEqualityComparer其中T:EntityModel
然后,您可以将其与Distinct()一起使用,以从T类型的任何IQueryable中筛选重复项,其中T是实体类。复杂类型不能从EntityModel继承,因为它没有ID属性,但这很好,因为您无论如何都不会对其使用distinct

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

public class GenericModelFilter<T> : where T : EntityModel
公共类GenericModelFilter:其中T:EntityModel
哦,等等,你的复杂类型不是EntityModel类型。现在,您必须使实体继承树复杂化,以适应复杂类型,或者摆脱EntityModel契约并降低可见性

接下来,您将向类中添加一个方法,该方法基于用户选择,可以创建一个表达式,用于linq过滤任何实体类

Expression<Func<T, bool>> GetPredicate() { ... }
表达式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;
personFilter=新的GenericModelFilter();
companyFilter=新的GenericModelFilter();
addressFilter=新的GenericModelFilter()//人的复杂类型
...
var query=来自context.Persons.Where(personFilter.GetPredicate())中的p
在p.CompanyID=c.ID上的context.companys.Where(companyFilter.GetPredicate())中加入c
选择p;
这对所有实体对象都适用。。。除了满足其特殊需要。你不能像加入公司那样加入。您可以从Person导航到它,但如何将该表达式应用到它上,并且仍然以Person结尾?现在,您必须花点时间,找出这个简单系统的特例,这个系统在其他任何地方都可以轻松工作


此模式在项目的整个生命周期中重复。我是凭经验说话的吗?我希望我没有。复杂类型会阻止你的进步,就像一个行为不端的学生坐在教室后面,却没有添加任何实质内容。帮自己一个忙,选择实际的实体对象。

拥有实体对象有什么好处