英文:
Why does C# think EF Include() returns a nullable object?
问题
以下是您提供的文本的中文翻译部分:
"Include的文档位于1:"
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;
但是对于以下代码行:
numCountySignups = context.Counties.Include(c => c.Events).ThenInclude(e => e.Signups).First(c => c.Id == county.Id).Events.Sum(ee => ee.Signups.Count);
我收到了警告:
严重性 Code 描述 项目 文件 行 抑制状态
警告 CS8620 不能将类型为'IIncludableQueryable<County, ICollection<Event>?>'的参数用于类型为'IIncludableQueryable<County, IEnumerable<Event>>'的参数'source'中的'IIncludableQueryable<County, Event, ICollection<Signup>?> EntityFrameworkQueryableExtensions.ThenInclude<County, Event, ICollection<Signup>?>(IIncludableQueryable<County, IEnumerable<Event>> source, Expression<Func<Event, ICollection<Signup>?>> navigationPropertyPath)',因为引用类型的nullability存在差异。 IntegrationTests C:\git\LouisHowe\IntegrationTests\repository\TestCounty.cs 203 Active
如果我添加一个!,警告就消失了:
numCountySignups = context.Counties.Include(c => c.Events)!.ThenInclude(e => e.Signups).First(c => c.Id == county.Id).Events.Sum(ee => ee.Signups.Count);
由于Include()的声明显示它是非空的,为什么会收到此警告呢?
英文:
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?
答案1
得分: 1
文档引用您提供的是来自EF 5(.Net Framework)而不是EF Core。对于EF Core,特别是在6.0之前的版本,使用NRT可能会导致编译器警告,这可能会带来问题。如果您正在使用EF Core 5,则应考虑升级到EF Core 6或7。
一个细节是确保在您的实体中初始化所有集合导航属性:
public class County
{
// ...
public virtual ICollection<Event> Events { get; private set; } = new List<Event>();
}
最后,您提供的示例查询是获取Sum的一种特别低效的方式:
numCountySignups = context.Counties
.Include(c => c.Events)
.ThenInclude(e => e.Signups)
.First(c => c.Id == county.Id)
.Events.Sum(ee => ee.Signups.Count);
这会将给定县的所有事件和注册加载到内存中,只是为了获取注册计数的总和。相反:
numCountySignups = context.Counties
.Where(c => c.Id == county.Id)
.Select(c => c.Events.Sum(ee => ee.Signups.Count))
.First();
这将构建并执行针对数据库的SQL语句,仅检索该总和。
英文:
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.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论