Entity Framework如何按嵌套子集合元素总数排序查询Top10用户
问题
我使用 Entity Framework 在数据库中创建了三张关联表,对应实体类定义如下:
class User{ public string Name {get;set;} public IEnumerable<Pet> Pets {get;set;} }
class Pet{ public string Name {get;set;} public IEnumerable<Toy> Toys {get;set;} }
class Toy{ public string Name {get;set;} }
当前需求为使用LINQ查询选取拥有玩具总数量最多的前10位用户。
最初尝试的查询语句执行失败,Entity Framework无法将该语句翻译为合法的SQL查询:
Entities .OrderBy(u => u.Pets.Select(n => n.Toys.Count())) .ToListAsync();
正确实现方案
原语句无法执行的核心原因有两点:
- 排序方向错误:
OrderBy是升序排序逻辑,要取玩具总数最高的用户需使用降序方法OrderByDescending - 排序字段不符合要求:
u.Pets.Select(n => n.Toys.Count())返回的是整数集合,不是单个可排序的聚合值,EF无法将集合类型的排序表达式翻译为合法SQL。
直接对每个用户名下所有宠物的玩具数量做求和聚合,再按聚合值降序取前10即可,EF 3.0及以上版本都可以正常将该语句翻译为标准SQL:
// 仅查询前10位用户实体 var top10Users = await Entities .OrderByDescending(u => u.Pets.Sum(p => p.Toys.Count())) .Take(10) .ToListAsync();
如果需要同时返回每个用户的玩具总数值,可以使用投影查询:
// 返回用户实体+对应玩具总数 var top10Result = await Entities .Select(u => new { UserInfo = u, TotalToyCount = u.Pets.Sum(p => p.Toys.Count()) }) .OrderByDescending(res => res.TotalToyCount) .Take(10) .ToListAsync();
如果存在导航属性为null的场景,可以加空值兜底避免运行时报错:
u.Pets.Sum(p => p.Toys?.Count() ?? 0)
内容的提问来源于stack exchange,提问作者user19291301
相关产品推荐
相关产品推荐

