2016-04-29 12 views
3

abfragt Ich weiß, dass viel in EF6 gearbeitet wurde, um asynchrone Operationen wie CountAsync zu unterstützen, aber ich kann scheinen, eine einfache Abfrage nicht zu annullieren. Hier ist die Geschichte.Wie man ein großes DbSet mit AsNoTracking und einem CancellationToken

Ich habe eine Abfrage, die 4,5 Millionen Zeilen zurückgibt. Ich muss jede Zeile verarbeiten, aber ich kann nicht alle im Speicher halten. EF6 ist nett genug, um dies zu tun, lassen Sie mich:

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

Dies funktioniert gut und verbraucht sehr wenig Speicher, aber es ist nicht sehr einfach zu stornieren. Ich habe versucht, diese Albernheit:

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

Natürlich, das versucht, lädt die gesamte Abfrage in eine Liste <> die lange abstürzt, bevor alle Zeilen geladen werden. Zum Glück reagiert es sehr auf eine Absage. :)

Die nächstgelegene ich bekommen habe, ist das ganze Durcheinander so wickeln:

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

Diese nicht-Speicher nicht kauen und ich kann abbrechen, aber die Löschung dauert ewig zu reagieren und es gibt einige eklige Ausnahmen, weil ich die Decke herausziehe.

Was fehlt mir hier?

+0

Wann Sie abbrechen können, wollen - noch bevor erste Zeile empfangen wird oder während der Verarbeitung? – Evk

+0

@Evk - Beide. Dies funktioniert in einem Service und die Stornierungsanfrage könnte jederzeit eingehen. –

+0

"dauert ewig", weil es nichts wirklich annulliert. Sobald die Task gestartet wurde, kann sie nicht mehr ausgeführt werden. .NET hat keine nicht kooperative Löschung. – usr

Antwort

2

Sie können es wie folgt tun:

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

Danke !!! Klappt wunderbar. Es war problematisch, mit all den verschiedenen Ausnahmen umzugehen, die hier ausgehuscht wurden, aber ich glaube, ich habe es verstanden. Ich musste die übliche OperationCancelledException, AggregateExceptions mit OperationCancelledExceptions, InnerExceptions mit OperationCancelledExceptions und (meine Favoriten) DataExceptions mit meiner SQL-Datenbank (Oracle) behandeln. Zu viel Spaß, oder? –