Sha*_*ica 17 c# linq aggregate linq-to-sql
我有一个Linq集合Things
,其中Thing
有一个Amount
(十进制)属性.
我正在尝试针对特定事物的子集对此进行聚合:
var total = myThings.Sum(t => t.Amount);
Run Code Online (Sandbox Code Playgroud)
这很好用.但后来我添加了一个条件,让我在结果中没有任何东西:
var total = myThings.Where(t => t.OtherProperty == 123).Sum(t => t.Amount);
Run Code Online (Sandbox Code Playgroud)
而不是得到total = 0或null,我得到一个错误:
System.InvalidOperationException:无法将null值分配给类型为System.Decimal的成员,该成员是非可空值类型.
这真是令人讨厌,因为我没想到这种行为.我本来期望总数为零,也许是null - 但肯定不会抛出异常!
我究竟做错了什么?什么是解决方法/修复?
编辑 - 例子
感谢大家的评论.这是一些代码,复制和粘贴(未简化).它是LinqToSql(也许这就是为什么你无法重现我的问题):
var claims = Claim.Where(cl => cl.ID < 0);
var count = claims.Count(); // count=0
var sum = claims.Sum(cl => cl.ClaimedAmount); // throws exception
Run Code Online (Sandbox Code Playgroud)
Cra*_*ntz 23
我可以使用针对Northwind的以下LINQPad查询重现您的问题:
Employees.Where(e => e.EmployeeID == -999).Sum(e => e.EmployeeID)
Run Code Online (Sandbox Code Playgroud)
这里有两个问题:
Sum()
超载了在SQL中,SUM(no rows)
返回null
,而不是零.但是,查询的类型推断会将您decimal
作为类型参数而不是decimal?
.修复是帮助类型推断选择正确的类型,即:
Employees.Where(e => e.EmployeeID == -999).Sum(e => (int?)e.EmployeeID)
Run Code Online (Sandbox Code Playgroud)
现在Sum()
将使用正确的重载.
要获得不可为空的结果,您需要将数量转换为可空类型,然后处理Sum
返回null 的情况.
decimal total = myThings.Sum(t => (decimal?)t.Amount) ?? 0;
Run Code Online (Sandbox Code Playgroud)
还有另一个专门讨论(ir)理由的问题.