Foreword:

我有两个项目.NET Core 3.1,一个EF Core 3.1.17,另一个在5.0.10上,在这两个版本中,我都使用了Include/thenClude,方式相同,一切都很好.

Problem:

当我试图在表达式中使用ThenClude语句时,当EF生成查询时,ThenClude中的所有实体都被忽略.

这是我的表达:

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在生成查询之前识别所有ThenClude语句(我try 在可能的地方添加更多语句,得到了相同的结果),有跟踪日志(log):

 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())'

但生成的结果看起来像:

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
)'

正如我们在这里看到的,thenClude语句中的实体"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);

    }
}

Question:

在EF Core版本3.1.17和5.0.10中使用thenClude有什么区别?为什么相同的表达式适用于第一个版本,但不适用于另一个版本?也许我做错了什么,或者在更改框架版本时忘记了更改什么?

P、 在我的第二个项目中,从EF Core 5.0.10开始,所有包含Include/thenClude语句的表达式都做得很好.

推荐答案

这说明了为什么在问题中包含所有代码很重要.

这是GetRegionRoles方法:

public IQueryable<RegionRole> GetRegionRoles(SystemCodesEnum systemId)
{
    return _context.RegionRole
        .Include(x => x.SystemRole)
        .Where(w => w.SystemRole.SystemId.Equals((int)systemId));
}

所以它已经包含了一个Include,同样的Include在您的查询中重复:

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

当我复制这段代码时,我看到,显然,EF对Include条语句的位置很敏感.在这种情况下,类似的包含由Where语句分隔.不知何故,这导致EF(核心5)忽略重复的Include(后面是ThenInclude).如果只需移动Where语句,就可以删除分隔:

public IQueryable<RegionRole> GetRegionRoles(SystemCodesEnum systemId)
{
    return _context.RegionRole
        .Where(w => w.SystemRole.SystemId.Equals((int)systemId))
        .Include(x => x.SystemRole);
}

我假设这不是故意的行为(为什么会这样?).你可能想发布一个bug报告,或者看看它是否仍然在版本6中发生.

Csharp相关问答推荐

C#中的包版本控制

下拉图片点击MudBlazor

获取ASP.NET核心身份认证cookie名称

使用两个不同的枚举作为Switch语句中的CASE生成唯一值

在调整大小的控件上绘制

从ASP.NET Core中的枚举字段填充 Select 选项时,将默认的第一个选项添加为 Select 元素

在静态模式下实例化配置

为什么Regex.IsMatch(";\\t";,";\\t";)返回FALSE而不是TRUE?

是否有必要在ASP.NET Core中注册可传递依赖项?

Linux Docker上的.NET6在某个时间抛出后,在加密操作期间发生System.Security.Cryptography.CryptographicException:错误

MSTest--将消息直接写入StdOut和使用TestContext有什么不同?

链接到字典字符串.拆分为(.Key,.Value)

如何将%{v_扩展}转换为%{v_扩展}>>

Blazor:搜索框在第一次搜索时不搜索

Visual Studio 17.8.0制表符自动完成问题--三缩进

Xamarin Forms应用程序中登录页面的用户名和密码编辑文本之间不需要的空格

ASP.NET核心中的授权,如何在DbContext启动之前提供租用ID

除非首先访问使用的终结点,否则本地API上的终结点不起作用

为什么我的UserControl没有加载到我的主窗口中?

在Swagger中显示自定义属性的属性名称