如何在LINQ to Entities查询中填充嵌套列表?
解决LINQ to Entities中初始化包含子列表的自定义类型问题
问题根源
EF6无法将查询内部的ToList()调用转换为SQL语句,因为List<T>是客户端内存中的集合类型,LINQ to Entities仅支持能转换为SQL的服务器端操作,直接在查询内初始化实现IEnumerable的类型会触发你遇到的异常。
修正后的查询代码
List<ParentModel> parentModelList = (from c in _context.children join p in _context.parents on c.ParentId equals p.ParentId where p.GenderId == gender.GenderId // 修正原代码的赋值运算符为比较运算符 orderby c.BirthDate group c by p into childGroup // 服务器端投影为匿名类型,不初始化List select new { Parent = childGroup.Key, Children = childGroup.Select(x => new { x.ChildId, x.ChildName }) }) // 切换到客户端内存处理 .AsEnumerable() // 转换为目标自定义类型,此时可安全调用ToList()初始化子列表 .Select(anon => new ParentModel() { ParentId = anon.Parent.ParentId, // 其他Parent属性从anon.Parent中映射 ChildList = anon.Children.Select(x => new ChildModel() { ChildId = x.ChildId, ChildName = x.ChildName }).ToList() }) .ToList();
关键修正点
- 避免查询内初始化集合:先在服务器端完成分组和基础投影,得到包含Parent和子元素序列的匿名类型,保持
IQueryable让EF生成正确的SQL。 - 切换到客户端处理:通过
AsEnumerable()将查询切换到内存中执行,此时可以使用ToList()等客户端方法初始化List<ChildModel>。 - 修正原代码逻辑错误:
- 分组后需通过
childGroup.Key访问分组依据的Parent实体,原代码直接使用p会编译报错。 - 子元素的
ChildId和ChildName应取自分组内的每个Child对象(x),而非分组Key或分组的第一个元素,原代码此处逻辑错误会导致所有子元素信息重复。 - 原代码
where子句使用了赋值运算符=,需修正为比较运算符==。
- 分组后需通过
额外优化建议
如果EF实体类中已定义Parent和Child的导航属性(比如Parent.Children),可以简化查询,避免手动join:
List<ParentModel> parentModelList = _context.parents .Where(p => p.GenderId == gender.GenderId) .Select(p => new { p, Children = p.Children.OrderBy(c => c.BirthDate) }) .AsEnumerable() .Select(anon => new ParentModel() { ParentId = anon.p.ParentId, // 其他Parent属性映射 ChildList = anon.Children.Select(c => new ChildModel() { ChildId = c.ChildId, ChildName = c.ChildName }).ToList() }) .ToList();
内容的提问来源于stack exchange,提问作者Tim
相关产品推荐
相关产品推荐

