SQL左连接分组统计转LINQ后FirstOrDefault返回null报错解决
SQL转LINQ查询空引用报错解决方案
问题背景
需要将如下统计SQL转换为LINQ语句:
SELECT dbo.Transactions.TypeRefID, dbo.TransactionItems.ItemRefID, SUM(dbo.TransactionItems.Quantity) AS Qty FROM dbo.TransactionItems LEFT OUTER JOIN dbo.Transactions ON dbo.TransactionItems.TransactionRefID = dbo.Transactions.TransactionID GROUP BY dbo.Transactions.TypeRefID, dbo.TransactionItems.ItemRefID HAVING (dbo.Transactions.TypeRefID = 1) AND (dbo.TransactionItems.ItemRefID = 5)
初始编写的LINQ实现代码如下:
var query = from t in db.Transaction join i in db.TransactionItem on t.TransactionID equals i.TransactionRefID where t.TypeRefID == 1 && i.ItemRefID == 5 group i by new { t.TypeRefID, i.ItemRefID } into g select new { TypeRefID = g.Key.TypeRefID, ItemRefID = g.Key.ItemRefID, Quantity = g.Sum(q => q.Quantity) };
运行时抛出System.Linq.Queryable.FirstOrDefault(...) returned null错误,调用逻辑如下,错误触发点为query.FirstOrDefault().Quantity.ToString():
if (query != null) string qty = query.FirstOrDefault().Quantity.ToString();
问题原因&修复方案
报错来自两个核心问题:
- 连接逻辑错误:原始SQL是
TransactionItems左外连接Transactions,初始LINQ写反了主表,还使用了默认的内连接,和SQL逻辑不匹配,可能漏数据或者查询结果不符合预期。 - 空值判断逻辑无效:
query本身是IQueryable类型对象,只要声明就不会为null,写的if (query != null)完全没有防护作用。当数据库没有匹配的查询结果时,FirstOrDefault()会返回null,直接访问null对象的Quantity属性就会抛出空引用错误。
第一步:修正LINQ查询逻辑,对齐SQL的左外连接
var query = from i in db.TransactionItem // 实现TransactionItem左连接Transaction join t in db.Transaction on i.TransactionRefID equals t.TransactionID into joinRes from t in joinRes.DefaultIfEmpty() // 左连接后t可能为null,做空值兼容 where (t == null ? 0 : t.TypeRefID) == 1 && i.ItemRefID == 5 group i by new { TypeRefID = t == null ? 0 : t.TypeRefID, i.ItemRefID } into g select new { TypeRefID = g.Key.TypeRefID, ItemRefID = g.Key.ItemRefID, Quantity = g.Sum(q => q.Quantity) };
第二步:修正调用时的空值判断
不要直接链式访问FirstOrDefault()返回结果的属性,先判断返回值是否为null,同时给无匹配结果的场景设置默认值:
string qty = "0"; // 无匹配数据时的默认数量 var result = query.FirstOrDefault(); if (result != null) { qty = result.Quantity.ToString(); }
内容的提问来源于stack exchange,提问作者Amiel
相关产品推荐
相关产品推荐

