2016-04-29 9 views
3

CountAsyncなどの非同期操作をサポートするためにEF6で多くの作業が行われていますが、単純な照会をキャンセルできないようです。ここにその話があります。AsNoTrackingとCancellationTokenで大規模なDbSetを照会する方法

450万行を返すクエリがあります。私は各行を処理する必要がありますが、それらをすべてメモリに保持することはできません。

これはうまく動作し、メモリはほとんど使用されませんが、キャンセルするのはあまり簡単ではありません。もちろん

foreach (var row in context.TableX.AsNoTracking().ToListAsync(token).Result) 
{ 
...process each row 
} 

が、これはしようとするすべての行が読み込まれ、長い前にクラッシュしたリスト<>にクエリ全体をロードします。私はこの愚かを試してみました。ありがたいことに、キャンセルに非常に敏感です。 :)

私が得ている最も近い、このような全体の混乱をラップすることです:

Task.Run(() => DoQuery(), token); 

これは、メモリをかむいないと私、それを取り消すことができますが、キャンセルが応答するために永遠にかかります私は敷物を引っ張っているので、いくつかの厄介な例外があります。

私はここで何が欠けていますか?

+0

- でも最初の行が受信される前または処理中に? – Evk

+0

@Evk - 両方。これはサービス内で動作しており、キャンセル要求はいつでも入力できます。 –

+0

実際には何もキャンセルしないので、「永遠に」となります。タスクの実行が開始されたら、それを呼び出す方法はありません。 .NETには非協調的な取り消しはありません。 – usr

答えて

2

あなたはこのようにそれを行うことができます:あなたがキャンセルできるようにしたいんとき

public async Task DoQuery(CancellationToken token) { 
    await ctx.TableX.AsNoTracking().ForEachAsync(row => 
    { 
     // process here 
    }, token); 
} 
+0

ありがとうございます!魅力のように動作します。これがうまくいったさまざまな例外をすべて処理することは問題だったが、私はそれを得たと思う。通常のOperationCancelledException、OperationCancelledExceptionsを含むAggregateExceptions、OperationCancelledExceptionsであるInnerExceptions、およびSQLデータベース(Oracle)によって投げられた(私のお気に入りの)DataExceptionsを処理する必要がありました。あまりにも楽しい、ええ? –