Wie schreibe ich eine asynchrone LINQ-Abfrage?
Nachdem ich gelesen habe eine Reihe von LINQ-related stuff, plötzlich merkte ich, dass keine Artikel einführen, wie Sie zum schreiben asynchroner LINQ-Abfrage.
Nehmen wir an, wir verwenden von LINQ to SQL, unterhalb Aussage ist klar. Allerdings, wenn der SQL-Datenbank langsam reagiert, dann wird der thread mit dieser code-block würde behindert werden.
var result = from item in Products where item.Price > 3 select item.Name;
foreach (var name in result)
{
Console.WriteLine(name);
}
Scheint, dass die aktuellen LINQ-query-Spezifikation nicht unterstützen.
Gibt es eine Möglichkeit, um asynchrone Programmierung LINQ? Es funktioniert, wie es ist ein callback
Benachrichtigung, wenn die Ergebnisse sind einsatzbereit-ohne blocking-delay auf der I/O.
InformationsquelleAutor der Frage Morgan Cheng | 2008-10-31
Du musst angemeldet sein, um einen Kommentar abzugeben.
Während LINQ nicht wirklich per se der Rahmen selbst nicht... Sie können einfach Rollen Sie Ihre eigenen asynchrone Abfrage Testamentsvollstrecker in 30 Zeilen oder so... In der Tat, ich warf gerade diese für Sie zusammen 🙂
EDIT: Durch das schreiben dieses, ich habe entdeckt, warum Sie nicht umsetzen. Es nicht in den Griff anonyme Typen, da Sie den Gültigkeitsbereich lokaler. So haben Sie keine Möglichkeit zum definieren der callback-Funktion. Dies ist eine ziemlich große Sache, da eine Menge von linq to sql-Inhalte erstellt, werden Sie in der select-Klausel. Einer der folgenden Vorschläge, die das gleiche Schicksal erleiden, also ich immer noch denke, das ist am einfachsten zu verwenden!
EDIT: Die einzige Lösung ist nicht zu verwenden, anonyme Typen. Sie können erklären, den Rückruf als nur IEnumerable (kein Typ args), und verwenden Sie reflektion, um auf die Felder (ICK!!). Ein anderer Weg wäre zu erklären, den Rückruf als "dynamische"... oh... warte... Das ist noch nicht aus. 🙂 Das ist ein anderes anständiges Beispiel, wie dynamische verwendet werden könnten. Manche nennen es Missbrauch.
Werfen Sie diese in Ihrem utilities-Bibliothek:
Und Sie können es verwenden, wie diese:
Gehen, setzen Sie diese auf meinem blog nun, ziemlich praktisch.
InformationsquelleAutor der Antwort TheSoftwareJedi
TheSoftwareJedi und ulrikb's(aka user316318) Lösungen sind gut für alle LINQ-Typ, aber (wie bereits von Chris Moschini) tun, NICHT delegieren zu Grunde liegenden asynchrone Aufrufe, die nutzen Windows I/O Completion Ports.
Wesley Bakker ist Asynchrone DataContext post (ausgelöst durch ein blog-post von Scott Hanselman ) beschreiben Klassen für LINQ to SQL verwendet sqlCommand.BeginExecuteReader/sqlCommand.EndExecuteReader, die nutzen Windows I/O Completion Ports.
I/O completion ports bieten eine effiziente threading-Modell für die Verarbeitung von mehreren asynchronen I/O-Anfragen auf einem Multiprozessor-system.
InformationsquelleAutor der Antwort Michael Freidgeim
Basierend auf Michael Freidgeim Antwort und erwähnt blog-post von Scott Hansellman und die Tatsache, dass Sie verwenden können
async
/await
die Sie umsetzen können wiederverwendbareExecuteAsync<T>(...)
Methode, die ausgeführt wird, zugrunde liegendenSqlCommand
asynchron:Und dann können Sie (wieder -) verwenden Sie es wie diese:
InformationsquelleAutor der Antwort Nenad
Begann ich eine einfache github-Projekt mit dem Namen Asynq asynchrone LINQ-to-SQL-Abfrageausführung. Die Idee ist ganz einfach-wenn auch "spröde" zu diesem Zeitpunkt (wie von 8/16/2011):
IQueryable
in eineDbCommand
über dieDataContext.GetCommand()
.DbCommand
Instanz, die Sie vonGetCommand()
zu bekommenSqlCommand
. Wenn Sie mit SQL-CE-Sie haben Pech, daSqlCeCommand
nicht aussetzen async-pattern fürBeginExecuteReader
undEndExecuteReader
.BeginExecuteReader
undEndExecuteReader
aus derSqlCommand
mit dem standard .NET framework asynchrone I/O-Muster, um sich selbst einDbDataReader
im Abschluss callback-Delegaten, den Sie an dieBeginExecuteReader
Methode.DbDataReader
denen wir keine Ahnung haben, welche Spalten es enthält noch, wie die Zuordnung dieser Werte zu sichern, um dieIQueryable
'sElementType
(die meisten wahrscheinlich ein anonymer Typ im Falle von joins). Sicher, an diesem Punkt könnten Sie hand-schreiben Sie Ihre eigene Spalte mapper materialisiert seine Ergebnisse wieder in Ihren anonymen Typ oder was auch immer. Sie müssten, um ein neues zu schreiben pro Abfrage-Ergebnis geben, je nachdem, wie LINQ-to-SQL behandelt Ihre IQueryable und was SQL-code, den es erzeugt. Dies ist eine ziemlich Fiese option, und ich empfehle es nicht, da es nicht verwaltbar es wäre auch nicht immer richtig. LINQ-to-SQL kann ändern Sie Ihre Abfrage, Formular, je nachdem die Werte der parameter, den Sie übergeben, zum Beispielquery.Take(10).Skip(0)
produziert verschiedene SQL alsquery.Take(10).Skip(10)
und vielleicht einen anderen resultset-schema. Ihre beste Wette ist, um diese zu bewältigen Materialisierung problem programmatisch:DbDataReader
in einer definierten Reihenfolge nach dem LINQ-to-SQL-mapping von Attributen desElementType
Typ für dieIQueryable
. Die Umsetzung dieser korrekt ist wohl der schwierigste Teil dieser Lösung.Als andere entdeckt haben, die
DataContext.Translate()
Methode nicht behandeln, anonyme Typen und kann nur eine KarteDbDataReader
direkt an eine ordnungsgemäß zurückgeführt LINQ-to-SQL-proxy-Objekt. Da die meisten Abfragen Wert, schriftlich in LINQ gehen, um komplexe joins, die unausweichlich, dass anonyme Typen für die abschließende select-Klausel, es ist ziemlich sinnlos, diese zu verwenden, vorausgesetzt verwässertenDataContext.Translate()
Methode sowieso.Gibt es ein paar kleine Nachteile bei dieser Lösung, wenn die Nutzung der bestehenden Reifen LINQ-to-SQL, das IQueryable-Anbieter:
IQueryable
z.B.from x in db.Table1 select new { a = x, b = x }
. LINQ-to-SQL-intern verfolgt die Spalte Ordnungszahlen Karte, um die Eigenschaften; ist es nicht aussetzen diese Informationen, um die Endbenutzer-also Sie haben keine Ahnung, welche Spalten in derDbDataReader
wiederverwendet werden und die "distinct".DbDataReader
so hätten Sie zum erstellen von benutzerdefinierten Logik zu ziehen, diese Konstanten Werte aus derIQueryable
'sExpression
Baum, das wäre ziemlich mühsam und ist einfach nicht vertretbar.Ich bin sicher, es gibt andere Abfrage-Muster, die vielleicht brechen, aber diese sind die zwei größten die ich mir vorstellen könnte, dass könnte zu Problemen führen, in eine bestehende LINQ-to-SQL-data-access-layer.
Diese Probleme sind leicht zu besiegen - einfach nicht tun Sie in Ihren Abfragen, da es keine Muster gibt keinen Vorteil, um das Ergebnis der Abfrage. Hoffentlich wird dieser Rat gilt für alle query-Muster, die potenziell zu Objekt Materialisierung Probleme :-P. Es ist ein schwieriges problem zu lösen, dass Sie keinen Zugang zu LINQ-to-SQL-Spalte mapping-Informationen.
Mehr "komplett" Ansatz zur Lösung des Problems wäre, um effektiv zu re-implementieren fast alle LINQ-to-SQL, das ist ein bisschen mehr Zeit in Anspruch :-P. ab einer Qualität, open-source-LINQ-to-SQL-provider-Implementierung wäre ein guter Weg, hier zu gehen. Der Grund, warum Sie brauchen, um zu implementieren ist es so, dass Sie hätten Zugang zu allen von der Spalte mapping-Informationen verwendet, um zu materialisieren, die
DbDataReader
Ergebnisse wieder bis auf ein Objekt-Instanz, ohne den Verlust von Informationen.InformationsquelleAutor der Antwort James Dunne