gpt4 book ai didi

c# - EF Core 5 - 查询中 Include()/Where() 方法的顺序是否重要?

转载 作者:行者123 更新时间:2023-12-04 14:57:44 28 4
gpt4 key购买 nike

我正在从 .NET Core 2.2 升级到 .NET 5.0 一个主要版本(2.2 -> 3.0 -> 3.1 -> 5.0),并且我有一个对 MySQL 数据库的 LINQ 查询,在升级到 5.0 后工作方式有所不同。该查询在 2.2、3.0 和 3.1 中工作正常,但在升级到 5.0 后 Include() 之一调用似乎没有任何效果。查询是:

var adminClient = (this._context.AdminUserClients
.Include(f => f.Client)
.Where(f => f.User.Id == user.Id && f.Client.Id != 1)
.Include(f => f.Client.ClientUserRoles) // This Include does not seem to have an effect
.ThenInclude(f => f.User)
.FirstOrDefault())?.Client;
(有关模型,请参见下文。)
当它在 EF Core 3.1(2.2 和 3.0 相似)中运行时,它会生成一个带有两个子查询的 SQL 语句,一个连接 AdminUserClients , AspNetUsers , 和 Clients ,一加入 ClientUserRolesAspNetUsers .然后,它连接两个子查询以生成结果。在 EF Core 5.0 中,生成的 SQL 语句不引用 ClientUserRoles --它本质上只是3.1 SQL语句中的第一个子查询。
如果我修改查询以移动 Where()调用后 Include()调用,它的工作原理:
var adminClient = (this._context.AdminUserClients
.Include(f => f.Client)
.Include(f => f.Client.ClientUserRoles) // This Include runs fine
.ThenInclude(f => f.User)
.Where(f => f.User.Id == user.Id && f.Client.Id != 1)
.FirstOrDefault())?.Client;
在这种情况下,生成的 SQL 语句实际上与 3.1 中生成的 SQL 语句相同。
我不确定为什么这会有所不同。也许是 UserWhere() 中引用对象之前需要包含它方法?但这对我来说没有意义,因为(1)它适用于 2.2、3.0 和 3.1,并且(2)我的理解是方法的顺序是 Include() 的相对顺序。和 Where()方法不应该影响返回集(尽管我知道它会影响性能)。
问题
  • Include()的顺序有问题吗?和 Where()原始查询中的方法?
  • 从 EF Core 3.1 到 EF Core 5.0 的更改是否会导致此查询的行为发生更改?

  • 关于拆分查询的注意事项
    因为我是从 2.2 升级到 5.0,所以我用的是 UseQuerySplittingBehavior(QuerySplittingBehavior.SplitQuery)模仿 2.2 的行为。但是,我已经测试过:
  • 添加 AsSplitQuery()到查询。
  • 使用 UseQuerySplittingBehavior(QuerySplittingBehavior.SingleQuery) .
  • 删除 UseQuerySplittingBehavior()完全。
    在所有这些情况下,行为都是相同的。

  • 模型
    public class AdminUserClient
    {
    public long Id { get; set; }
    [Required]
    public ApplicationUser User { get; set; }
    [Required]
    public Client Client { get; set; }
    [Required]
    public DateTime CreatedOn { get; set; }
    }

    public class ApplicationUser : IdentityUser
    {
    public UserNotificationsSetting NotificationSetting { get; set; }
    [JsonIgnore]
    public ClientUserRole ClientUserRole { get; set; }
    public bool Locked { get; set; }
    public string Name { get; set; }
    }

    public class Client
    {
    public long Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public bool RequireTwoFactor { get; set; }
    public ApplicationUser CreatedBy { get; set; }
    public DateTime CreatedOn { get; set; }
    [JsonIgnore]
    public ICollection<ClientUserRole> ClientUserRoles { get; set; }
    public bool IsDeleted { get; set; }
    public bool Locked { get; set; }
    }

    public class ClientUserRole
    {
    public long Id { get; set; }
    [Required]
    public long ClientId { get; set; }
    [JsonIgnore]
    public Client Client { get; set; }
    [Required]
    public string UserId { get; set; }
    public ApplicationUser User { get; set; }
    [Required]
    public ApplicationUser CreatedBy { get; set; }
    [Required]
    public DateTime CreatedOn { get; set; }
    [Required]
    [Column(TypeName = "nvarchar(15)")]
    public UserRole Role { get; set; }
    }
    更新
    这已被一位贡献者确认为 EF Core 5.0 错误:请参阅 https://github.com/dotnet/efcore/issues/24953 .

    最佳答案

    根据定义(设计),Include 的相对顺序与其他 LINQ 查询运算符无关 - 唯一的要求是 Include用于启动查询的实体。
    因此,上述 EF Core 版本之间在这方面没有故意更改。然而,定义/设计是一回事,实现又是另一回事。简单地说,您遇到了 EF Core 5.x 错误,因此最好将其报告给他们的 GitHub 问题跟踪器。
    问题并不总是出现,似乎与Where中使用的表达式有关。谓词(通常 Include 不应影响过滤器、排序等 LINQ 运算符中导航属性的使用),更具体地说是导航属性 Client这里

    f.Client.Id != 1
    结合
    .Include(f => f.Client)
    如果您从 Where 中删除该条件,或移动 IncludeWhere有了这个条件,剩下的就包括工作。虽然有了这种组合,他们却没有。
    所以报告它以便让他们知道并最终修复它。在那之前,由于您无法删除条件(显然),请重新排序 Includes .
    如果您想安全(并且不想遇到类似的意外错误),即使定义不需要,也可以将所有 Includes在查询的开头,紧跟在 DbSet 之后, 然后是所有其他运算符。

    关于c# - EF Core 5 - 查询中 Include()/Where() 方法的顺序是否重要?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67626140/

    28 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com