Linq GroupBy含可空属性:如何跳过子列表中的空对象
问题分析与解决
我有一张包含两个引用类ID的Class1表,希望按Class2的两个属性分组,仅将非空的Class3添加到子列表。尝试两种Linq写法后仍无法跳过空项,列表中仍会出现空对象。
原始代码
var groupData = await _context.Class1 .Where(ct => ct.Id == Id && ct.C2 != null ) .Select(h => new { h.Class2.F1, h.Class2.F2, h.Class3 } ).ToListAsync(); var result = groupData.GroupBy(g => new { g.F1, g.F2 }).Select(h => new MyResult { F1 = h.Key.F1, F2 = h.Key.F2, F4List = h.Select(x =>new MyModel { C5F1 = x.Class3.F1, C5F2 = x.Class3.F2, C5F3 = x.Class3.F3, }).ToList() }).ToList();
修改后代码
var groupData = await _context.Class1 .Where(ct => ct.Id == Id && ct.C2 != null ) .Select(h => new { h.Class2.F1, h.Class2.F2, h.Class3 } ).ToListAsync(); var result = groupData.GroupBy(g => new { g.F1, g.F2 }).Select(h => new MyResult { F1 = h.Key.F1, F2 = h.Key.F2, F4List = h.Select(x => x.Class3 != null ? new MyModel { C5F1 = x.Class3.F1, C5F2 = x.Class3.F2, C5F3 = x.Class3.F3, }: null).ToList() }).ToList();
Class1结构
public class Class1 { int Id; int class2ID; int? class3ID; virtual Class2 Class2; virtual Class3 Class3; }
问题原因与解决方法
问题所在
- 原始代码:未过滤
Class3为空的项,直接创建MyModel,当x.Class3为空时会触发空引用异常,即使未抛出异常,也会生成无效的MyModel对象。 - 修改后代码:虽然判断了
x.Class3 != null,但空值场景返回null并直接加入列表,导致F4List中包含null元素,而非跳过这些项。
解决办法
生成F4List时,先通过Where过滤掉Class3为空的项,再执行Select创建MyModel:
var groupData = await _context.Class1 .Where(ct => ct.Id == Id && ct.Class2 != null) .Select(h => new { h.Class2.F1, h.Class2.F2, h.Class3 }) .ToListAsync(); var result = groupData .GroupBy(g => new { g.F1, g.F2 }) .Select(h => new MyResult { F1 = h.Key.F1, F2 = h.Key.F2, F4List = h.Where(x => x.Class3 != null) .Select(x => new MyModel { C5F1 = x.Class3.F1, C5F2 = x.Class3.F2, C5F3 = x.Class3.F3, }).ToList() }).ToList();
优化建议
可将过滤逻辑提前到EF查询阶段,减少内存处理的数据量,提升性能:
var result = await _context.Class1 .Where(ct => ct.Id == Id && ct.Class2 != null && ct.Class3 != null) .GroupBy(ct => new { ct.Class2.F1, ct.Class2.F2 }) .Select(g => new MyResult { F1 = g.Key.F1, F2 = g.Key.F2, F4List = g.Select(ct => new MyModel { C5F1 = ct.Class3.F1, C5F2 = ct.Class3.F2, C5F3 = ct.Class3.F3, }).ToList() }).ToListAsync();
内容的提问来源于stack exchange,提问作者Kamran Shahid
相关产品推荐
相关产品推荐

