Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does C# think EF Include() returns a nullable object?

The documentation for Include is:

public static System.Linq.IQueryable<T> Include<T,TProperty> (this System.Linq.IQueryable<T> source, System.Linq.Expressions.Expression<Func<T,TProperty>> path) where T : class;

But for the line of code:

numCountySignups = context.Counties.Include(c => c.Events).ThenInclude(e => e.Signups).First(c => c.Id == county.Id).Events.Sum(ee => ee.Signups.Count);

I get the warning:

Severity    Code    Description Project File    Line    Suppression State
Warning CS8620  Argument of type 'IIncludableQueryable<County, ICollection<Event>?>' cannot be used for parameter 'source' of type 'IIncludableQueryable<County, IEnumerable<Event>>' in 'IIncludableQueryable<County, ICollection<Signup>?> EntityFrameworkQueryableExtensions.ThenInclude<County, Event, ICollection<Signup>?>(IIncludableQueryable<County, IEnumerable<Event>> source, Expression<Func<Event, ICollection<Signup>?>> navigationPropertyPath)' due to differences in the nullability of reference types.  IntegrationTests    C:\git\LouisHowe\IntegrationTests\repository\TestCounty.cs  203 Active

which goes away if I add a ! as follows:

numCountySignups = context.Counties.Include(c => c.Events)!.ThenInclude(e => e.Signups).First(c => c.Id == county.Id).Events.Sum(ee => ee.Signups.Count);

As the declaration of Include() shows it to be non-nullable, why do I get this warning?

like image 801
David Thielen Avatar asked May 09 '26 12:05

David Thielen


1 Answers

The documentation reference you included was from EF 5 (.Net Framework) rather than EF Core. NRTs can be problematic in EF with compiler warnings, especially with EF Core prior to 6.0. If you are running EF Core 5 then you should look to upgrade to EF Core 6 or 7.

One detail is to ensure that all collection navigation properties are initialized in your entities:

public class County
{
    // ...

    public virtual ICollection<Event> Events { get; private set; } = new List<Event>();
}

Lastly, the example query you provided is a particularly inefficient way to get the Sum:

numCountySignups = context.Counties
    .Include(c => c.Events)
        .ThenInclude(e => e.Signups)
    .First(c => c.Id == county.Id)
    .Events.Sum(ee => ee.Signups.Count);

This loads all events and signups for the given county into memory just to get a sum of the signup count. Instead:

numCountySignups = context.Counties
    .Where(c => c.Id == county.Id)
    .Select(c => c.Events.Sum(ee => ee.Signups.Count))
    .First();

This would build and execute an SQL statement against the database to retrieve just that sum.

like image 161
Steve Py Avatar answered May 12 '26 12:05

Steve Py