You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EF Core 3.1升级5.0后ThenInclude生成查询被忽略问题

问题背景

有两个基于.NET Core 3.1的项目,分别运行EF Core 3.1.17与EF Core 5.0.10,两个项目中采用相同写法使用Include/ThenInclude方法,均能正常运行。近期尝试将使用EF Core 3.1.17的项目升级至5.0.10版本,遇到了异常问题。

问题现象

在查询表达式中使用ThenInclude语句时,EF Core生成查询的过程中会忽略ThenInclude指定的关联实体,不会关联查询对应表数据。

使用的查询表达式如下:

var settings = await _dbRepository.GetRegionRoles(systemId)
            .Include(r => r.Region)
            .Include(sr => sr.SystemRole)
            .ThenInclude(ro => ro.Role)
            .Include(gs => gs.GroupSettings)
            .Where(w => w.GroupSettings.Any())
            .ToListAsync(cancellationToken);

从跟踪日志可以看到,EF Core在编译查询表达式阶段能够识别所有ThenInclude语句(尝试在支持的位置添加更多ThenInclude语句,得到的结果一致),对应跟踪日志内容如下:

Compiling query expression: 
'DbSet<RegionRole>()
    .Include(x => x.SystemRole)
    .Where(w => w.SystemRole.SystemId.Equals((int)__systemId_0))
    .Include(r => r.Region)
    .Include(sr => sr.SystemRole)
    .ThenInclude(ro => ro.Role)
    .Include(gs => gs.GroupSettings)
    .Include(sr => sr.SystemRole)
    .ThenInclude(s => s.SystemCode)
    .Where(w => w.GroupSettings
        .Any())'

但最终生成的查询执行表达式中,并未包含ThenInclude关联的表JOIN逻辑,生成的查询执行表达式如下:

Generated query execution expression: 
'queryContext => new SingleQueryingEnumerable<RegionRole>(
    (RelationalQueryContext)queryContext, 
    RelationalCommandCache.SelectExpression(
        Projection Mapping:
        SELECT r.Id, r.CreatedByUser, r.CreatedDate //... and many other fields from each table
        FROM Main.RegionRole AS r
        INNER JOIN Main.SystemRole AS s ON r.SystemRoleId == s.Id
        INNER JOIN Main.Region AS r0 ON r.RegionId == r0.Id
        LEFT JOIN Main.GroupSettings AS g ON r.Id == g.RegionRoleId
        WHERE (s.SystemId == CAST(@__systemId_0) AS int)) && EXISTS (
            Projection Mapping:
            SELECT 1
            FROM Main.GroupSettings AS g0
            WHERE (r.Id != NULL) && (r.Id == g0.RegionRoleId))
        ORDER BY r.Id ASC, s.Id ASC, r0.Id ASC, g.Id ASC), 
    Func<QueryContext, DbDataReader, ResultContext, SingleQueryResultCoordinator, RegionRole>, 
    K2Project.BE.DAL.Models.K2DbContext, 
    False, 
    False
)'

从生成的表达式可以看出,ThenInclude语句关联的Role实体在最终查询中缺失,没有被关联查询。
所有实体均配置了正确的导航属性,通过Fluent API完成了实体映射,所有数据库表均已配置对应外键。

以下是SystemRole实体的定义示例:

public class SystemRole
{        
    public Guid Id { get; set; }

    public int RoleId { get; set; }        

    #region Dependencies

    public virtual Role Role { get; set; }

    #endregion
 }

该实体对应的Fluent API配置如下:

public class SystemRoleEntityTypeConfiguration : IEntityTypeConfiguration<SystemRole>
{
    public void Configure(EntityTypeBuilder<SystemRole> builder)
    {
        builder.ToTable(nameof(SystemRole), DbConst.MainSchemaName);

        builder.HasKey(p => p.Id);

        builder.Property(p => p.Id)
            .ValueGeneratedOnAdd()
            .HasDefaultValueSql("NEWSEQUENTIALID()");

        builder.HasOne(p => p.Role)
            .WithMany()
            .HasForeignKey(f => f.RoleId)
            .IsRequired(true);

    }
}
咨询问题
  • EF Core 3.1.17与5.0.10版本中ThenInclude的运行逻辑存在什么差异?
  • 为什么完全相同的查询表达式在3.1.17版本可正常运行,升级到5.0.10版本后就无法加载ThenInclude指定的关联实体?
  • 是否是升级框架版本时遗漏了必要的配置或调整?

补充说明:另有一个从初始搭建就使用EF Core 5.0.10的项目,其中所有Include/ThenInclude语句均能正常运行,无上述问题。


问题原因与解决方案

这个问题本质是EF Core 5.0升级后查询管道的行为变更,问题出在自定义仓储的返回逻辑上:

  • EF Core 3.1的查询管道逻辑比较直接,只要代码里写了Include/ThenInclude,不管查询链路里有没有其他包装逻辑,基本都会按配置生成对应JOIN。5.0版本做了性能优化,会自动裁剪它判定为“无效”的Include操作——如果GetRegionRoles方法返回的不是EF Core原生追踪的IQueryable,比如方法内部提前做了枚举、投影,或者自定义的IQueryable包装丢失了EF的查询提供器标记,后面链式写的ThenInclude就会被当成无效逻辑直接忽略,根本不会生成对应JOIN。
  • 原生搭建的5.0项目没有该问题,是因为所有查询都是直接从DbSet开始链式调用,全程都是EF原生的IQueryable实例,Include的标记不会在链路中丢失。

修复按以下步骤排查即可:

  1. 先检查GetRegionRoles的实现,确认方法内部没有调用ToList()、AsEnumerable()这类会提前触发查询的方法,必须直接返回基于DbSet<RegionRole>构建的原生IQueryable,不能先查询出结果再转成IQueryable返回。
  2. 如果仓储层对IQueryable做了自定义包装,检查包装类有没有正确实现EF Core 5.0新增的IAsyncQueryProvider接口,避免在传递表达式树的时候把Include/ThenInclude的方法节点意外筛除。
  3. 最快的验证方式:把这段查询直接改成从DbContext.Set<RegionRole>()开始编写,跳过仓储层,如果能正常生成Role表的JOIN,就可以确认是仓储封装和EF Core 5.0不兼容的问题,调整仓储实现即可。
  4. 顺便检查DbContext配置,确认没有给Role实体配置会自动过滤的全局查询过滤器,排除过滤器导致的JOIN裁剪。

内容的提问来源于stack exchange,提问作者sir drake

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 16:09:23