在执行带有分页和大量过滤器的查询之前,我对其调用
.CountAsync()
。事实证明,对于某些过滤条件,.CountAsync()
需要很长时间才能完成(因为必要的连接),并且拥有可用数量的优势并不重要,值得长时间等待。
因此我决定取消那些需要超过一秒的场景的计数并继续实际查询。
var tokenSource = new CancellationTokenSource();
var ct = tokenSource.Token;
var totalCountTask = query.CountAsync(ct);
var finishedTask = await Task.WhenAny(totalCountTask, Task.Delay(1000));
var totalCount = 0;
if (finishedTask == totalCountTask)
{
totalCount = await totalCountTask;
}
else
{
tokenSource.Cancel();
}
items = await query
.Skip((filter.Page - 1) * filter.PageSize)
.Take(filter.PageSize)
.ToListAsync();
但是在取消计数操作的情况下,下一个查询执行会抛出异常:
System.InvalidOperationException:“在上一个操作完成之前,在此上下文实例上启动了第二个操作。 ...
但即使任务被成功取消(我在调试模式下检查过),似乎之前的查询仍在后台运行,阻止了
DbContext
做其他工作。
取消查询后是否有可能“释放”
DbContext
以便能够再次使用它?
查询中止后,需要等待中止完成。否则,第二个查询可能会在中止完成之前开始。
if (finishedTask == totalCountTask)
{
totalCount = await totalCountTask;
}
else
{
tokenSource.Cancel();
try
{
await totalCountTask;
}
catch // swallow the exception from the abort
{ }
}