当可能存在空集时如何进行 Linq 聚合?
我有一个 Things
的 Linq 集合,其中 Thing
有一个 Amount
(十进制)属性。
我正在尝试对事物的某个子集进行聚合:
var total = myThings.Sum(t => t.Amount);
效果很好。但后来我添加了一个条件,结果中没有任何东西:我
var total = myThings.Where(t => t.OtherProperty == 123).Sum(t => t.Amount);
得到的不是 Total = 0 或 null,而是错误:
System.InvalidOperationException:无法将空值分配给 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
I have a Linq collection of Things
, where Thing
has an Amount
(decimal) property.
I'm trying to do an aggregate on this for a certain subset of Things:
var total = myThings.Sum(t => t.Amount);
and that works nicely. But then I added a condition that left me with no Things in the result:
var total = myThings.Where(t => t.OtherProperty == 123).Sum(t => t.Amount);
And instead of getting total = 0 or null, I get an error:
System.InvalidOperationException: The null value cannot be assigned to
a member with type System.Decimal which is a non-nullable value type.
That is really nasty, because I didn't expect that behavior. I would have expected total to be zero, maybe null - but certainly not to throw an exception!
What am I doing wrong? What's the workaround/fix?
EDIT - example
Thanks to all for your comments. Here's some code, copied and pasted (not simplified). It's LinqToSql (perhaps that's why you couldn't reproduce my problem):
var claims = Claim.Where(cl => cl.ID < 0);
var count = claims.Count(); // count=0
var sum = claims.Sum(cl => cl.ClaimedAmount); // throws exception
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我可以使用以下针对 Northwind 的 LINQPad 查询重现您的问题:
这里有两个问题:
Sum()
重载在 SQL 中,
SUM(no rows)
返回null
,而不是零。但是,查询的类型推断会为您提供decimal
作为类型参数,而不是decimal?
。修复是为了帮助类型推断选择正确的类型,即:现在将使用正确的
Sum()
重载。I can reproduce your problem with the following LINQPad query against Northwind:
There are two issues here:
Sum()
is overloadedIn SQL,
SUM(no rows)
returnsnull
, not zero. However, the type inference for your query gives youdecimal
as the type parameter, instead ofdecimal?
. The fix is to help type inference select the correct type, i.e.:Now the correct
Sum()
overload will be used.要获得不可为 null 的结果,您需要将 amount 转换为可为 null 的类型,然后处理
Sum
返回 null 的情况。还有另一个问题专门讨论(ir)基本原理。
To get a non-nullable result, you need to cast the amount to a nullable type, and then handle the case of
Sum
returning null.There's another question devoted to the (ir)rationale.
它会抛出异常,因为组合 sql 查询的结果为 null,并且不能将其分配给十进制 var。如果您执行以下操作,那么您的变量将为空(我假设 ClaimedAmount 是十进制):
那么您应该获得您想要的功能。
您还可以在 where 语句处执行 ToList(),然后总和将返回 0,但这将与其他地方关于 LINQ 聚合的说法相冲突。
it throws an exception because the result of the combined sql query is null and this cant be assigned to the decimal var. If you did the following then your variable would be null (I assume ClaimedAmount is decimal):
then you should get the functionality you desire.
You could also do ToList() at the point of the where statement and then the sum would return 0 but that would fall foul of what has been said elsewhere about LINQ aggregates.
如果 t 具有像“HasValue”这样的属性,那么我会将表达式更改为:
If t has a property like a 'HasValue', then I would change the expression to: