Tomas Aschan
Tomas Aschan

Reputation: 60604

How do I coalesce .Max() for queries against empty collections in LINQ to EF?

I have an entity in my model that has an integer property:

public class Foo
{
    public int SortOrder { get; set; }

    // ...other props
}

Now, for some subset of all the Foos in the database, I want to select the highest SortOrder and add one - i.e. get the sort order for a new object added last in the collection - but if there are no Foos in that subset, I want to end up with 0 - i.e. the sort order of a new object added to an empty collection.

Reading this reference page, I got the impression that .Max() returns null if the collection over which it aggregates is empty, so I tried the following:

var sortOrder = context.Foos
    .Where(/* predicate for subset */)
    .Max(foo => foo.SortOrder) + 1
    ?? 0;

but that doesn't compile, since the return type of .Max is inferred to be int which can't be null coalesced.

However, if I just don't use the null coalescing, and assume that .Max() really returns default(T) (i.e. 0 in this case), then I'll end up with 1 instead of 0 for the empty case. Since this is a call to the database, I'd rather make do with one query.

It works just as I want it to if I make the property on Foo to be of type int?, but I don't want to do that since we don't allow NULL values in the database and I see no reason to allow them on the entity then.

Upvotes: 1

Views: 641

Answers (1)

Tim Schmelter
Tim Schmelter

Reputation: 460158

I got the impression that .Max() returns null if the collection over which it aggregates is empty

You get an InvalidOperationException which is documented here

"InvalidOperationException... source does not contain any elements."

You can use DefaultIfEmpty(0):

int maxSortOrder = context.Foos
    .Where(/* predicate for subset */)
    .Select(foo => foo.SortOrder + 1)
    .DefaultIfEmpty(0)
    .Max();

Upvotes: 3

Related Questions