EF Core如何通过显式加载加载多级嵌套关联实体
EF Core 预加载写法对应的显式加载等效实现
原始预加载代码
以下是使用Include/ThenInclude实现预加载的原始代码:
var movie = await context .Movies .AsNoTracking() .Include(m => m.Genres) .Include(m => m.CinemaHalls) .ThenInclude(ch => ch.Cinema) .Include(m => m.MovieActors) .ThenInclude(ma => ma.Actor) .FirstOrDefaultAsync(m => m.Id == id);
你当前的实现进度
你已经完成了根实体和第一层集合导航属性的加载:
var movie = await context .Movies .FirstOrDefaultAsync(m => m.Id == id); if (movie is null) return; await context.Entry(movie).Collection(m => m.Genres).LoadAsync(); await context.Entry(movie).Collection(m => m.CinemaHalls).LoadAsync(); await context.Entry(movie).Collection(m => m.MovieActors).LoadAsync();
完整等效显式加载实现
嵌套层级的关联加载逻辑很直接:加载完当前层级的实体后,遍历每一个已加载的父实体,根据导航属性类型选择对应方法加载即可:
- 集合类型导航属性使用
Collection()方法加载 - 单个引用类型导航属性使用
Reference()方法加载
注意:要和原始预加载行为完全一致,需要在根实体查询时加上
AsNoTracking(),避免实体被上下文追踪。
// 查询根实体,保持和原代码一致的无追踪配置 var movie = await context .Movies .AsNoTracking() .FirstOrDefaultAsync(m => m.Id == id); if (movie is null) return; // 加载直接关联的Genres集合 await context.Entry(movie).Collection(m => m.Genres).LoadAsync(); // 加载CinemaHalls集合,再逐个加载每个影厅关联的Cinema引用 await context.Entry(movie).Collection(m => m.CinemaHalls).LoadAsync(); foreach (var cinemaHall in movie.CinemaHalls) { await context.Entry(cinemaHall).Reference(ch => ch.Cinema).LoadAsync(); } // 加载MovieActors集合,再逐个加载每个演职人员关联条目对应的Actor引用 await context.Entry(movie).Collection(m => m.MovieActors).LoadAsync(); foreach (var castEntry in movie.MovieActors) { await context.Entry(castEntry).Reference(ma => ma.Actor).LoadAsync(); }
如果需要优化性能减少数据库查询次数,也可以手动批量查询所有关联的Cinema、Actor实体后,手动绑定到已加载的实体导航属性上,上面的写法是严格对应EF Core显式加载API的实现,运行效果和Include/ThenInclude预加载完全一致。
内容的提问来源于stack exchange,提问作者Display Name
相关产品推荐
相关产品推荐

