EF6中Linq to Entities使用投影仍查询所有列的问题求助
解决Linq to Entities投影仍查询视图所有列的问题
我之前在使用EDMX映射SQL Server视图时,也碰到过一模一样的问题——明明写了select new做投影,生成的SQL却还是会把视图的所有列都查出来。结合我的踩坑经验,给你几个可行的解决方案:
1. 给视图设置正确的实体主键
这是最常见的原因!EF如果检测到映射的视图没有主键(或者主键不唯一),会把它当成“无键实体”。为了确保能正确追踪实体,EF会默认查询视图的所有列,哪怕你做了投影。
解决步骤:
- 打开你的EDMX文件,在模型浏览器里找到
vStudentProfiles视图对应的实体 - 右键实体→属性,在“实体键”选项里,勾选一个或多个能唯一标识每条记录的列(比如
intStudentId) - 保存EDMX并重新生成代码,再运行查询试试
2. 给查询添加AsNoTracking()
因为你用的是匿名类型投影,完全不需要EF的实体追踪功能。加上AsNoTracking()后,EF会知道不需要追踪这些实体,从而优化SQL生成,只查询你需要的列。
修改后的查询代码:
var students = (from x in db.vStudentProfiles.AsNoTracking() where x.strLegalFirstName == searchDTO.FirstName && x.strLegalMiddleName == searchDTO.MiddleName && x.strLegalLastName == searchDTO.LastName && x.datBirthDate == searchDTO.DateOfBirth && x.intStudentStatusCd != 3 orderby x.intStudentStatusCd ascending, x.datCreated descending select new { x.strLegalFirstName, x.strLegalLastName, x.strLegalMiddleName, x.datBirthDate, x.intStudentStatusCd, x.datCreated, x.strNBEN }).ToList();
3. 使用DbQuery<T>替代实体映射(EF6专属)
如果你不需要对这个视图做增删改操作,只是用来查询,可以用EF6的DbQuery<T>来映射视图,它专门用于只读查询,不会触发实体追踪,能更好地优化投影。
操作步骤:
- 创建一个只包含你需要列的类:
public class StudentProfileProjection { public string strLegalFirstName { get; set; } public string strLegalLastName { get; set; } public string strLegalMiddleName { get; set; } public DateTime datBirthDate { get; set; } public int intStudentStatusCd { get; set; } public DateTime datCreated { get; set; } public string strNBEN { get; set; } }
- 在你的DbContext里添加:
public DbQuery<StudentProfileProjection> vStudentProfiles { get; set; }
- 在EDMX里把视图映射到这个
StudentProfileProjection类(确保只映射需要的列)
之后再执行查询,生成的SQL就只会包含你指定的列了。
4. 禁用延迟加载和代理创建(辅助优化)
有时候EF的延迟加载和代理创建会干扰查询优化,你可以在DbContext的构造函数里加上这两行:
public YourDbContext() : base("YourConnectionString") { this.Configuration.LazyLoadingEnabled = false; this.Configuration.ProxyCreationEnabled = false; }
这能让EF更专注于你写的投影逻辑,减少不必要的全列查询。
内容的提问来源于stack exchange,提问作者Andrew Grothe
相关产品推荐
相关产品推荐

