EFCore 编译的查询不能使用 orderby linq 语句



当我尝试编译这个测试代码时:

using Microsoft.EntityFrameworkCore;
using var db = new InventoryContext();
await db.AddAsync<Item>(new() { Name = "Table", Description = "A wooden office Table with a cup holder", Type = ItemType.Furniture });
await db.SaveChangesAsync();
Console.WriteLine("Showing all entries:");
Func<InventoryContext, IAsyncEnumerable<Item>> compiled = EF.CompileAsyncQuery((InventoryContext db) => from item in db.Items orderby item.Id select item);
IAsyncEnumerable<Item> items = compiled(db);
await foreach (Item item in items)
{
Console.WriteLine(item.Id);
Console.WriteLine(item.Name);
Console.WriteLine(item.Type);
Console.WriteLine(item.Description is null ? "*no description*" : item.Description);
Console.WriteLine();
}

它告诉我"System.Func<DatabaseTest。InventoryContext>;

将第10行更改为

Func<InventoryContext, IAsyncEnumerable<Item>> compiled = EF.CompileAsyncQuery((InventoryContext db) => db.Items.OrderBy(x => x.Id));

也不会起作用,只有在添加。select (x=>x)或删除顺序部分时才会起作用。有人可以解释为什么(至少它看起来对我来说)一个有序的语句不能在编译查询中使用?

这个问题与IOrderedQueryable, IAsyncEnumerable和CompileQueryAsync之间的不兼容无关。

没有EF过载。CompileQueryAsync接受一个IOrderedQueryable,因此选择一个返回TResult的重载,可能是这个:

Func<TContext,Task<TResult>> CompileAsyncQuery<TContext,TResult> (
Expression<Func<TContext,TResult>> queryExpression)

也有一个接受DbSet<T>的过载:

CompileAsyncQuery<TContext,TResult>(Expression<Func<TContext,DbSet<TResult>>>)

我们需要的重载是:

CompileAsyncQuery<TContext,TResult>(Expression<Func<TContext,IQueryable<TResult>>>)

同时存在Func<>Expression<Func<>>重载,因此最好的选择是分别显式地定义表达式,以确保使用正确的重载。代码也更简洁了。


Expression<Func<InventoryContext,IQueryable<Item>>> queryExpression = 
db => from item in db.Items 
orderby item.Id 
select item;
var compiled =EF.CompileAsyncQuery(queryExpression);

整个代码段编译没有问题:

IQueryable<Item> ItemsQuery(InventoryContext db) => 
from item in db.Items 
orderby item.Id 
select item;
Expression<Func<InventoryContext,IQueryable<Item>>> queryExpression = 
db => from item in db.Items 
orderby item.Id 
select item;
var compiled =EF.CompileAsyncQuery(queryExpression);
var db = new InventoryContext();
var items = compiled(db);
await foreach (Item item in items)
{
Console.WriteLine(item.Id);
}

确保结果是可查询的。简单地将AsQueryable()添加到查询的末尾即可解决问题:

Func<InventoryContext, IAsyncEnumerable<Item>> compiled = 
EF.CompileAsyncQuery((InventoryContext db) => 
(from item in db.Items orderby item.Id select item).AsQueryable());

最新更新