EF Core预加载通过include和ThenInclude一次性加载关联数据以解决N+1问题:Include用于一级关联,ThenInclude用于多级嵌套,支持多种组合;需注意分页前调用、避免数据膨胀、慎用全量加载。

EF Core 预加载(Eager Loading)就是用 Include 主动把关联数据一次性查出来,避免访问导航属性时反复查库——这是解决 N+1 查询问题最直接有效的方式。
Include 基本用法:加载一级关联
只需在查询链中调用 .Include(x => x.NavigationProperty),EF Core 就会在生成 sql 时自动加 JOIN 或发批量查询:
- 对引用类型(如
Post.Author),通常生成 LEFT JOIN - 对集合类型(如
Blog.Posts),默认用单独的 IN 查询(避免笛卡尔积),也可配成 JOIN - 必须用 Lambda 表达式,不能写字符串,否则编译不通过
示例:
var posts = context.Posts .Include(p => p.Author) .Include(p => p.Comments) .ToList();
ThenInclude:加载多级嵌套关系
当关联再往下一层(比如作者还有 Profile,评论还有 Reply),就得接 ThenInclude:
- 它只能跟在
Include或上一个ThenInclude后面 - 每级都必须指向“上一级导航属性”的子属性,类型要严格匹配
- 支持集合→引用、集合→集合、引用→引用等组合
示例(三级加载):
var blogs = context.Blogs .Include(b => b.Posts) // Blog → Posts(集合) .ThenInclude(p => p.Author) // Posts → Author(引用) .ThenInclude(a => a.Profile) // Author → Profile(引用) .ToList();
同时加载多个同级导航属性
一个实体常有多个独立的一级关联,比如博客既有文章,又有标签、分类:
- 重复调用
Include即可,顺序无关 - EF Core 会为每个
Include生成独立的 JOIN 或批量查询 - 注意:不要对同一个导航属性多次
Include,会报错
示例:
var blogs = context.Blogs .Include(b => b.Posts) .Include(b => b.Tags) .Include(b => b.Category) .ToList();
实用提醒:别踩这些坑
预加载不是越多越好,几个关键点得心里有数:
- 分页前一定要先
Include,否则Take(10)可能因 JOIN 导致结果重复或数量不准 - 一对多关系下过度
Include容易引发数据膨胀(比如 1 个博客 + 100 篇文章 + 每篇 5 条评论 = 500 行结果) - 不需要全部字段时,优先考虑
select投影,比全量Include更轻量 - 若只想查部分子项(如只加载最近 3 条评论),
Include本身不支持过滤,得换思路(如用 GroupJoin 或显式查询)
基本上就这些。用好 Include 和 ThenInclude 不复杂,但容易忽略时机和层级约束。