Search code examples
c#entity-framework-corelinq-to-entitiesentity-framework-core-3.0

Using Average returns "The sequence has no elements"


I have the following Entity Framework 3.0 query:

var result = await posts
   .Where(x => x.Published.HasValue)
   .DefaultIfEmpty()
   .AverageAsync(x => x.Published.Day);

When posts has no elements I get the error:

The sequence has no elements

The Post class is:

public class Post {
  public Int32 Id { get; set; }
  public DateTime? Published { get; set; }
}

This seemed to work when using Entity Framework Core 2.2.

Is there a way to make this work?


Solution

  • This seemed to work when using Entity Framework Core 2.2

    You are right, this seems to have been broken in EF Core 3.0.

    I personally never liked the usage of DefaultIfEmpty for avoiding "The sequence has no elements" LINQ to Objects exception with LINQ aggregate methods Average, Min and Max. Instead I prefer using cast to promote the nullable overloads which are known to return null in such cases, rather than throwing exception. It's also the natural SQL behavior of these aggregate methods, hence is almost always translated correctly, including EF Core 3.0.

    Applying it to the query in question:

    var result = await posts
       .Where(x => x.Published.HasValue)
       .AverageAsync(x => (int?)x.Published.Value.Day);
    

    Note that the type of the result now is nullable, so use ?? operator if you need to convert it to some magic number, e.g.

    return result ?? 0