如何用LINQ方法语法实现4层深度Eager Loading预加载
解决Eager Loading多层关联与筛选问题
首先先修正下类定义里的小笔误(C类的集合应该命名为Ds才和其他集合命名统一):
public class A { public int Id; public ICollection<B> Bs; } public class B { public int Id; public int AId; public ICollection<C> Cs; } public class C { public int Id; public int BId; public ICollection<D> Ds; } public class D { public int Id; public int CId; public bool Show; }
1. 一次性Eager Loading所有关联数据(对应你的TSQL逻辑)
要实现多层嵌套的预加载,你需要用Include + ThenInclude的链式写法,这会让EF生成和你给出的LEFT JOIN逻辑一致的SQL,并且只执行一次数据库查询。正确的LINQ方法语法如下:
var result = db.A .Include(a => a.Bs) // 加载A关联的所有B集合 .ThenInclude(b => b.Cs) // 加载每个B关联的所有C集合 .ThenInclude(c => c.Ds) // 加载每个C关联的所有D集合 .FirstOrDefault(a => a.Id == 1);
这个查询会一次性拉取所有层级的关联数据,完全匹配你给出的TSQL查询效果,确保只触发一次数据库调用。
2. 筛选出Show == true的D数据
如果需要在数据库层面就筛选出Show=true的D(而非加载所有D后再在内存中过滤),在EF Core 5及以上版本可以直接使用带条件的Include:
var result = db.A .Include(a => a.Bs) .ThenInclude(b => b.Cs) .ThenInclude(c => c.Ds.Where(d => d.Show)) // 仅加载Show为true的D .FirstOrDefault(a => a.Id == 1);
如果是使用EF6(不支持带条件的Include),可以通过投影来实现类似效果:
var result = db.A .Where(a => a.Id == 1) .Select(a => new { A = a, Bs = a.Bs.Select(b => new { B = b, Cs = b.Cs.Select(c => new { C = c, Ds = c.Ds.Where(d => d.Show) }) }) }) .FirstOrDefault();
之后你可以把投影结果转换回实体类,或者直接使用这个匿名类型进行后续操作。
常见问题提醒
- 你原代码里写了
a.B,但类定义里是集合Bs,要注意命名一致性,避免加载错误或空引用。 - 多层嵌套预加载一定要用
ThenInclude,而非在Include里嵌套Select,后者是早期EF的写法,现在ThenInclude的可读性和规范性更好。
内容的提问来源于stack exchange,提问作者RoLYroLLs
相关产品推荐
相关产品推荐

