当我尝试编译这个测试代码时:
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());