如何使用 AsNoTracking 和 CancellationToken 查询大型 DbSet
How to query a large DbSet with AsNoTracking and a CancellationToken
我知道在 EF6 中做了很多工作来支持 CountAsync 等异步操作,但我似乎无法取消简单的查询。这是故事。
我有一个查询 returns 450 万行。我需要处理每一行,但我不能将它们全部保存在内存中。 EF6 好心让我这样做:
foreach (var row in context.TableX.AsNoTracking())
{
...process each row
}
这很好用并且占用的内存很少,但是取消起来不是很容易。我试过这种愚蠢的做法:
foreach (var row in context.TableX.AsNoTracking().ToListAsync(token).Result)
{
...process each row
}
当然,这会尝试将整个查询加载到一个 List<> 中,该列表在加载所有行之前很久就崩溃了。值得庆幸的是,它对取消非常敏感。 :)
我最接近的是像这样包装整个混乱:
Task.Run(() => DoQuery(), token);
这不会占用内存,我 可以 取消它,但取消需要永远响应,并且有一些讨厌的例外,因为我正在拉地毯。
我在这里错过了什么?
你可以这样做:
public async Task DoQuery(CancellationToken token) {
await ctx.TableX.AsNoTracking().ForEachAsync(row =>
{
// process here
}, token);
}
我知道在 EF6 中做了很多工作来支持 CountAsync 等异步操作,但我似乎无法取消简单的查询。这是故事。
我有一个查询 returns 450 万行。我需要处理每一行,但我不能将它们全部保存在内存中。 EF6 好心让我这样做:
foreach (var row in context.TableX.AsNoTracking())
{
...process each row
}
这很好用并且占用的内存很少,但是取消起来不是很容易。我试过这种愚蠢的做法:
foreach (var row in context.TableX.AsNoTracking().ToListAsync(token).Result)
{
...process each row
}
当然,这会尝试将整个查询加载到一个 List<> 中,该列表在加载所有行之前很久就崩溃了。值得庆幸的是,它对取消非常敏感。 :)
我最接近的是像这样包装整个混乱:
Task.Run(() => DoQuery(), token);
这不会占用内存,我 可以 取消它,但取消需要永远响应,并且有一些讨厌的例外,因为我正在拉地毯。
我在这里错过了什么?
你可以这样做:
public async Task DoQuery(CancellationToken token) {
await ctx.TableX.AsNoTracking().ForEachAsync(row =>
{
// process here
}, token);
}