views:

80

answers:

3

Given this query:

from s in services
select new
{
    s.Id,
    s.DateTime,
    Class = s.Class.Name,
    s.Location,
    s.Price,
    HeadCount = s.Reservations.Sum(r => r.PartySize), // problem here. r.PartySize is int
    s.MaxSeats
}

If the service doesn't have any reservations, this exception is thrown:

System.InvalidOperationException: The cast to value type 'Int32' failed because the materialized value is null. Either the result type's generic parameter or the query must use a nullable type.

I get it, but how should I deal with it? My intention is if there are no reservations, then HeadCount be assigned 0.

+4  A: 

You should check for it:

HeadCount = s.Reservations != null ? s.Reservations.Sum(r => r.PartySize) : 0,
Ahmad Mageed
I posted this question before trying that just because I assumed that LINQ to Entites wouldn't be able to convert it to SQL or something like that. I'm still getting used to L2E, which seems much more picky than LINQ to SQL was about what you could actually do inside the LINQ statement. Anyway, this works and one should never assume. Thanks.
Ronnie Overby
@Ronnie glad it worked. They're definitely different and I imagine L2E will only become more flexible in the future.
Ahmad Mageed
This will work, but there's an easier solution.
Craig Stuntz
@Ronnie, @Craig: the way I read the question I understood that `Reservations` itself might be null. I did however come across this [blog post](http://adventuresinsoftware.com/blog/?p=478) that shows an EF 1.0 issue with summing empty sets. The solution involves casting to a nullable and using the null coalescing operator. Just thought I would mention it in case I overlooked something. I think this has been fixed since EF1.0 though.
Ahmad Mageed
You need to think of this in terms of how it will be translated to SQL, not in terms of the rules of C#. L2E plays by different rules than L2O. There is no such thing as a null reference exception in L2E as nulls are automatically coalesced.
Craig Stuntz
@Craig thanks, that makes sense since it's translated. I was indeed thinking in terms of L2O/C#.
Ahmad Mageed
+1  A: 

A simple ternary operator should fix the problem nicely...

something like this:

HeadCount = s.Reservations.Count == 0 ? 0 : s.Reservations.Sum(r => r.PartySize),
Justin Williams
I don't think that code will even compile (missing `()`). It certainly won't produce efficient SQL (never use `.Count() == 0` when you mean `Any()`), but even that is both inefficient and hard to read in comparison with. L2E's built-in null coalesce).
Craig Stuntz
You're right, it won't compile because Count is missing the '()'. Wrote it on the fly -_-. Any would also be more efficient. Thanks for the correction!
Justin Williams
+2  A: 

There's an even simpler solution:

from s in services
select new
{
    s.Id,
    s.DateTime,
    Class = s.Class.Name,
    s.Location,
    s.Price,
    HeadCount = (int?)s.Reservations.Sum(r => r.PartySize), 
    s.MaxSeats
}

Note the cast. This may also produce simpler SQL than @Ahmad's suggestion.

Essentially, you're just helping out type inference.

Craig Stuntz
According to the OP `Reservations` could be `null` so attempting to call `Sum(...)` on a null isn't possible. Casting to an `int?` wouldn't bypass the null exception that would occur at runtime. Perhaps you were thinking of casting a null value directly, like `(int?)r.PartySize`?
Ahmad Mageed
@Ahmad, that's not correct for L2E, although it is correct for L2O. They have different rules. No, I am not thinking of casting the value. Try the code I suggest; it does work.
Craig Stuntz
+1 I overlooked the translation that takes place for this LINQ provider.
Ahmad Mageed
+1 I like it . .
Ronnie Overby