Asynchrone Programmierung

Asynchrone Vorgänge vermeiden, dass ein Thread blockiert wird, während die Abfrage in der Datenbank ausgeführt wird. Asynchrone Vorgänge sind wichtig für die Beibehaltung einer reaktionsfähigen Benutzeroberfläche in Rich-Client-Anwendungen und können auch den Durchsatz in Webanwendungen erhöhen, in denen sie den Thread für die Bearbeitung anderer Anforderungen in Webanwendungen freigeben.

Nach dem .NET-Standard stellt EF Core asynchrone Gegenstücke für alle synchronen Methoden bereit, die E/A ausführen. Diese haben dieselben Effekte wie die synchronen Methoden und können mit C# async- und await-Schlüsselwörtern verwendet werden. Statt beispielsweise DbContext.SaveChanges zu verwenden, das einen Thread blockieren wird, während Datenbank-E/A ausgeführt wird, kann DbContext.SaveChangesAsync verwendet werden:

var blog = new Blog { Url = "http://sample.com" };
context.Blogs.Add(blog);
await context.SaveChangesAsync();

Weitere Informationen finden Sie in der allgemeinen Dokumentation zur asynchronen C#-Programmierung.

Warnung

EF Core unterstützt nicht die Ausführung mehrerer paralleler Vorgänge, die auf derselben Kontextinstanz ausgeführt werden. Sie sollten immer auf den Abschluss eines Vorgangs warten, bevor Sie den nächsten starten. In der Regel erfolgt dies für alle asynchronen Vorgänge durch das Schlüsselwort await.

Warnung

Die asynchrone Implementierung von Microsoft.Data.SqlClient weist einige bekannte Probleme auf (z. B. 593 und 601). Wenn unerwartete Leistungsprobleme auftreten, versuchen Sie stattdessen, die synchrone Befehlsausführung zu verwenden. Dies gilt insbesondere bei großen Text- oder Binärwerten.

Hinweis

EF Core gibt Abbruchtoken an den verwendeten Datenbankanbieter weiter (z. B. Microsoft.Data.SqlClient). Diese Token können berücksichtigt werden oder auch nicht – konsultieren Sie die Dokumentation Ihres Datenbankanbieters.

Asynchrone LINQ-Operatoren

Um die asynchrone Ausführung von LINQ-Abfragen zu unterstützen, stellt EF Core eine Reihe asynchroner Erweiterungsmethoden bereit, welche die Abfrage ausführen und Ergebnisse zurückgeben. Diese Gegenstücke zu den standardmäßigen, synchronen LINQ-Operatoren umfassen ToListAsync, SingleAsync, AsAsyncEnumerable usw.:

var blogs = await context.Blogs.Where(b => b.Rating > 3).ToListAsync();

Beachten Sie, dass es für einige LINQ-Operatoren, z. B. Where oder OrderBy, keine asynchronen Versionen gibt, da diese nur die LINQ-Ausdrucksbaumstruktur erstellen und nicht die Ausführung der Abfrage in der Datenbank auslösen. Nur Operatoren, welche die Abfrageausführung verursachen, weisen asynchrone Gegenstücke auf.

Wichtig

Die asynchronen Erweiterungsmethoden von EF Core werden im Namespace Microsoft.EntityFrameworkCore definiert. Dieser Namespace muss importiert werden, damit die Methoden verfügbar sind.

Clientseitige asynchrone LINQ-Operatoren

Die oben beschriebenen asynchronen LINQ-Operatoren können nur für EF-Abfragen verwendet werden – Sie können sie nicht mit einer clientseitigen LINQ to Objects-Abfrage verwenden. Verwenden Sie das System.Linq.Async-Paket, um clientseitige asynchrone LINQ-Vorgänge außerhalb von EF auszuführen. Dieses Paket kann besonders nützlich sein, um Vorgänge auf dem Client auszuführen, die nicht für die Auswertung auf dem Server übersetzt werden können.

In EF Core 6.0 und niedriger führt das Verweisen auf System.Linq.Async leider zu mehrdeutigen Aufrufkompilierungsfehlern für LINQ-Operatoren, die auf DBSets von EF angewendet werden. Dies macht es schwierig, sowohl EF als auch System.Linq.Async im selben Projekt zu verwenden. Um dieses Problem zu umgehen, fügen Sie AsQueryable Ihrem DbSet hinzu:

var groupedHighlyRatedBlogs = await context.Blogs
    .AsQueryable()
    .Where(b => b.Rating > 3) // server-evaluated
    .AsAsyncEnumerable()
    .GroupBy(b => b.Rating) // client-evaluated
    .ToListAsync();