Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
230 views
in Technique[技术] by (71.8m points)

c# - How to do Linq aggregates when there might be an empty set?

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
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I can reproduce your problem with the following LINQPad query against Northwind:

Employees.Where(e => e.EmployeeID == -999).Sum(e => e.EmployeeID)

There are two issues here:

  1. Sum() is overloaded
  2. LINQ to SQL follows SQL semantics, not C# semantics.

In SQL, SUM(no rows) returns null, not zero. However, the type inference for your query gives you decimal as the type parameter, instead of decimal?. The fix is to help type inference select the correct type, i.e.:

Employees.Where(e => e.EmployeeID == -999).Sum(e => (int?)e.EmployeeID)

Now the correct Sum() overload will be used.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...