您可以使用投影仅返回子列:
var result = from x in context.LargeTable
select new { x.Id, x.Name };
问题:投影和急加载无法同时使用。一旦您开始使用投影或自定义连接,您就会更改查询的形状,因此您无法使用
Include
(EF将忽略它)。在这种情况下唯一的方法是在投影的结果集中手动包含关系。
var result = from x in context.LargeTable
select new {
Id = x.Id,
Name = x.Name,
// You can filter or project relations as well
RelatedEnitites = x.SomeRelation.Where(...)
};
你也可以投影到特定类型,但该特定类型不得被映射(因此,例如无法从我的示例中将投影投射到
LargeTable
实体)。仅可在Linq-to-objects中的实现数据上对映射实体进行投影。
编辑:
可能有一些误解EF的工作方式。 EF建立在实体之上-实体就是你所映射的内容。如果你将500个列映射到实体,则EF只是按照你定义的实体来使用它。这意味着查询会加载实体并持久化保存实体。
为什么会这样呢?实体被认为是原子数据结构,其数据只能加载和跟踪一次-这是正确将更改持久化回数据库的关键特性。这并不意味着如果需要仅加载子集,则不应加载所有列,但是您应该了解,加载列子集不定义您的原始实体-它被视为对实体中数据的任意视图。此视图未被跟踪,并且不能在没有某些额外努力的情况下持久化回数据库(简单地因为EF不持有关于投影来源的任何信息)。
EF还对映射实体的能力施加了一些附加约束。
- 每个表只能被正常映射一次。为什么?因为将表映射多次到不同的实体可能会破坏正确持久化这些实体的能力——例如,如果任何非键列被映射两次,并且您加载了映射到同一记录的两个实体的实例,在保存更改时将使用哪个映射值?
- 有两个例外允许您多次映射表
- 层次结构继承 - 这是一种映射,其中表可以包含在继承层次结构中定义的多个实体类型的记录。映射到层次结构中基本实体的列必须由所有实体共享。每个派生实体类型都可以具有映射到其特定属性的自己的列(其他实体类型始终将这些列为空)。不可能在多个实体之间共享派生属性的列。还必须有一个名为鉴别器的附加列,告诉EF存储在记录中的实体类型 - 这些列不能映射为属性,因为它们已经映射为类型鉴别器。
- 表分割 - 这是单表映射限制的直接解决方案。它允许您将表拆分为多个实体,并带有一些约束:
- 实体之间必须存在一对一关系。您有一个中心实体用于加载核心数据,所有其他实体都可以通过此实体的导航属性访问。急切加载,延迟加载和显式加载正常工作。
- 关系是真正的1-1,因此关系的两个部分始终存在。
- 实体不能共享任何属性,除了键 - 此约束将解决最初的问题,因为每个可修改的属性仅映射一次
- 拆分表中的每个实体都必须具有映射的键属性
- 插入需要填充整个对象图,因为其他实体可能包含映射所需的列
Linq-to-Sql也包含将列标记为延迟加载的功能,但这个功能目前在EF中不可用-您可以
投票支持该功能。
它会影响您的优化选项
- 使用投影来获取实体的只读“视图”
- 您可以在Linq查询中执行此操作,就像我在上一部分答案中展示的那样
- 您可以创建数据库视图并将其映射为新的“实体”
- 在EDMX中,您还可以使用定义查询或查询视图来封装映射中的SQL或ESQL投影
- 使用表拆分
- EDMX允许您将表拆分为多个实体而不会出现任何问题
-
Code First也允许您拆分表,但是当您将表拆分为两个以上的实体时会出现一些问题(我认为它要求每个实体类型都有导航属性到来自拆分表的所有其他实体类型-这使得它非常难以使用)。