有关编译异步查询的在线文档和示例有点稀疏,所以我不妨在这里寻求指导。
假设我有一个像这样的存储库模式方法来查询表中的所有条目:
public async Task<List<ProgramSchedule>> GetAllProgramsScheduledList()
{
using (var context = new MyDataContext(_dbOptions))
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
return await context.ProgramsScheduledLists.ToListAsync();
}
}
这个效果很好。
现在我想做同样的事情,但是使用异步编译查询。
我设法编译它的一种方法是使用以下语法:
static readonly Func<MyDataContext, Task<List<ProgramSchedule>>> GetAllProgramsScheduledListQuery;
static ProgramsScheduledListRepository()
{
GetAllProgramsScheduledListQuery = EF.CompileAsyncQuery<MyDataContext, List<ProgramSchedule>>(t => t.ProgramsScheduledLists.ToList());
}
public async Task<List<ProgramSchedule>> GetAllProgramsScheduledList()
{
using (var context = new MyDataContext(_dbOptions))
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
return await GetAllProgramsScheduledListQuery(context);
}
}
但是在运行时会抛出此异常:
System.ArgumentException: Expression of type 'System.Collections.Generic.List`1[Model.Scheduling.ProgramSchedule]' cannot be used for return type 'System.Threading.Tasks.Task`1[System.Collections.Generic.List`1[Model.Scheduling.ProgramSchedule]]'
奇怪的是,如果我使用任何其他运算符(例如 SingleOrDefault),它工作正常。只是返回列表有问题。
为什么?
EF.CompileAsync
对于记录集,返回 IAsyncEnumrable<T>
。要从此类查询中获取 List
,您必须枚举 IAsyncEnumrable
并填写 List
,
private static Func<MyDataContext, IAsyncEnumerable<ProgramSchedule>> compiledQuery =
EF.CompileAsyncQuery((MyDataContext ctx) =>
ctx.ProgramsScheduledLists);
public static async Task<List<ProgramSchedule>> GetAllProgramsScheduledList(CancellationToken ct = default)
{
using (var context = new MyDataContext(_dbOptions))
{
context.ChangeTracker.QueryTrackingBehavior = QueryTrackingBehavior.NoTracking;
var result = new List<ProgramSchedule>();
await foreach (var s in compiledQuery(context).WithCancellation(ct))
{
result.Add(s);
}
return result;
}
}
Package System.Linq.Async 已针对此类情况预定义了扩展,
ToListAsync()
、ToArrayAsync()
等。