EF Core 默认启用懒加载时,如何正确实现导航属性的预先加载?
问题解答
你给出的Include写法是完全可用的,即便你全局开启了懒加载代理,预加载的优先级也更高,不会和懒加载配置冲突。
核心原理
EF Core 中Include方法的作用就是触发预加载,执行查询时会生成包含JOIN逻辑的SQL语句,一次性将主实体和你指定的关联导航属性数据全部拉取到内存中,后续访问这些已经预加载的导航属性时,不会再触发额外的数据库查询,完全满足你减少数据库请求次数的需求。
不同场景的正确实现
- 单层级导航属性预加载
就是你写的写法,注意异步调用需要加await,所在方法需要声明为async,完整示例:
// 异步查询必须加await,方法返回值改为Task<List<MyObject>> var dataList = await dbContext.MyObjects .Include(o => o.NavigationProperty) .ToListAsync();
如果需要同时加载多个同级导航属性,链式调用多个Include即可:
var dataList = await dbContext.MyObjects .Include(o => o.NavProp1) .Include(o => o.NavProp2) .ToListAsync();
- 嵌套多层导航属性预加载
如果需要加载导航属性下的子级关联数据,搭配ThenInclude方法实现:
// 加载MyObject -> NavProp -> SubNavProp的三级数据 var dataList = await dbContext.MyObjects .Include(o => o.NavProp) .ThenInclude(n => n.SubNavProp) .ToListAsync();
大型集合场景的优化建议
你提到处理的是大型对象集合,可结合以下方案进一步优化性能:
- 如果只需要用到实体和关联属性的部分字段,优先用
Select投影查询,不需要依赖预加载和懒加载,性能开销更低:
// 只查询需要的字段,避免加载冗余数据 var result = await dbContext.MyObjects .Select(o => new { o.Id, o.Title, NavContent = o.NavProp.Content }) .ToListAsync();
- 如果关联的是数据量较大的集合导航属性,可开启拆分查询避免笛卡尔积冗余数据,EF Core 5+ 支持:
var dataList = await dbContext.MyObjects .Include(o => o.LargeCollectionNavProp) .AsSplitQuery() // 拆分为主实体、关联集合两条SQL查询,避免大量重复数据 .ToListAsync();
- 如果查询后不需要修改实体,可追加
AsNoTracking关闭实体跟踪,既可以提升查询性能,也能避免误访问未预加载的导航属性时触发额外的懒加载查询。
内容的提问来源于stack exchange,提问作者Maksim
相关产品推荐
相关产品推荐

