布尔异步调用的 EF Core 3.1 客户端评估问题
EF Core 3.1 Client Side Evaluation Issue With Boolean Async Call
我正在从 .Net 2.1 迁移到 3.1,这包括 EF Core 升级。
现在我有如下 LINQ 查询,没有任何问题:
var application = await _db.CustomerApplications
.AsNoTracking()
.Include(i => i.CustomerApplicationFields)
.Include(i => i.Customer)
.Where(x => x.Customer.PublicId == formId && x.IsPublished) // Also tried with &
.OrderByDescending(o => o.Version)
.FirstOrDefaultAsync();
使用 EF Core 3.1 时出现错误:
The LINQ expression 'DbSet<CustomerApplication>
.Where(c => !(c.Deleted))
.Join(
outer: DbSet<Customer>
.Where(c0 => !(c0.Deleted)),
inner: c => EF.Property<Nullable<long>>(c, "CustomerId"),
outerKeySelector: c0 => EF.Property<Nullable<long>>(c0, "Id"),
innerKeySelector: (o, i) => new TransparentIdentifier<CustomerApplication, Customer>(
Outer = o,
Inner = i
))
.Where(c => c.Inner.PublicId == __formId_0 && c.Outer.IsPublished)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
当我按如下方式转换此查询时,它会起作用(将 bool
评估移到外部):
var application = await _db.CustomerApplications
.AsNoTracking()
.Include(i => i.CustomerApplicationFields)
.Include(i => i.Customer)
.Where(x => x.Customer.PublicId == formId)
.OrderByDescending(o => o.Version)
.ToListAsync();
var result = application.FirstOrDefault(x => x.IsPublished);
有人可以向我解释一下,为什么这是个问题?我也试过x.IsPublished == true
,没有效果。这似乎是相当随机的。
我也试过 AsTracking()
。
您应该使用 && 而不是 &,或者您可以添加另一个 where 子句。
在 EF Core 3.0 之前,无法转换为 SQL 查询的查询在客户端进行评估。现在,此行为已被取消并抛出异常,而不是在客户端评估不可翻译的查询。
此外,我认为当您编写 var result = application.FirstOrDefault(x => x.IsPublished);[=21= 时,新行为不应导致任何大的性能问题] 分开来说,因为之前也发生过同样的事情。只是之前不可见。 (假设有误请指正!)
如果你想有一个查询(没有测试这个),你也可以尝试以下:
var application = await _db.CustomerApplications
.AsNoTracking()
.Include(i => i.CustomerApplicationFields)
.Include(i => i.Customer)
.Where(x => x.Customer.PublicId == formId)
.OrderByDescending(o => o.Version)
.FirstOrDefaultAsync(x => x.IsPublished);
我正在从 .Net 2.1 迁移到 3.1,这包括 EF Core 升级。
现在我有如下 LINQ 查询,没有任何问题:
var application = await _db.CustomerApplications
.AsNoTracking()
.Include(i => i.CustomerApplicationFields)
.Include(i => i.Customer)
.Where(x => x.Customer.PublicId == formId && x.IsPublished) // Also tried with &
.OrderByDescending(o => o.Version)
.FirstOrDefaultAsync();
使用 EF Core 3.1 时出现错误:
The LINQ expression 'DbSet<CustomerApplication>
.Where(c => !(c.Deleted))
.Join(
outer: DbSet<Customer>
.Where(c0 => !(c0.Deleted)),
inner: c => EF.Property<Nullable<long>>(c, "CustomerId"),
outerKeySelector: c0 => EF.Property<Nullable<long>>(c0, "Id"),
innerKeySelector: (o, i) => new TransparentIdentifier<CustomerApplication, Customer>(
Outer = o,
Inner = i
))
.Where(c => c.Inner.PublicId == __formId_0 && c.Outer.IsPublished)' could not be translated. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync(). See https://go.microsoft.com/fwlink/?linkid=2101038 for more information.
当我按如下方式转换此查询时,它会起作用(将 bool
评估移到外部):
var application = await _db.CustomerApplications
.AsNoTracking()
.Include(i => i.CustomerApplicationFields)
.Include(i => i.Customer)
.Where(x => x.Customer.PublicId == formId)
.OrderByDescending(o => o.Version)
.ToListAsync();
var result = application.FirstOrDefault(x => x.IsPublished);
有人可以向我解释一下,为什么这是个问题?我也试过x.IsPublished == true
,没有效果。这似乎是相当随机的。
我也试过 AsTracking()
。
您应该使用 && 而不是 &,或者您可以添加另一个 where 子句。
在 EF Core 3.0 之前,无法转换为 SQL 查询的查询在客户端进行评估。现在,此行为已被取消并抛出异常,而不是在客户端评估不可翻译的查询。
此外,我认为当您编写 var result = application.FirstOrDefault(x => x.IsPublished);[=21= 时,新行为不应导致任何大的性能问题] 分开来说,因为之前也发生过同样的事情。只是之前不可见。 (假设有误请指正!)
如果你想有一个查询(没有测试这个),你也可以尝试以下:
var application = await _db.CustomerApplications
.AsNoTracking()
.Include(i => i.CustomerApplicationFields)
.Include(i => i.Customer)
.Where(x => x.Customer.PublicId == formId)
.OrderByDescending(o => o.Version)
.FirstOrDefaultAsync(x => x.IsPublished);