Schreiben der ersten LINQ-Abfrage (Visual Basic)
Aktualisiert: November 2007
Eine Abfrage ist ein Ausdruck, der Daten von einer Datenquelle abruft. Abfragen werden in einer dedizierten Abfragesprache ausgedrückt. Im Laufe der Zeit wurden verschiedene Sprachen für verschiedene Datenquellen entwickelt, beispielsweise SQL für relationale Datenbanken und XQuery für XML. Aus diesem Grund muss der Anwendungsentwickler für jeden Typ von Datenquelle oder Datenformat die jeweilige Abfragesprache erlernen.
Sprachintegrierte Abfrage (Language-Integrated Query, LINQ) vereinfacht diese Situation durch die Bereitstellung eines konsistenten Modells zum Arbeiten mit Daten in verschiedenen Arten von Datenquellen und Formaten. In einer LINQ-Abfrage arbeiten Sie immer mit Objekten. Sie verwenden dieselben grundlegenden Codierungsmuster für die Abfrage und Transformation von Daten in XML-Dokumenten, SQL-Datenbanken, ADO.NET-Datasets und -Entitäten, .NET Framework-Auflistungen sowie allen anderen Quellen und Formaten, für die ein LINQ-Anbieter verfügbar ist. In diesem Dokument werden die drei Phasen der Erstellung und die Verwendung grundlegender LINQ-Abfragen beschrieben.
Drei Phasen einer Abfrageoperation
LINQ-Abfrageoperationen bestehen aus drei Aktionen:
Abrufen der Datenquelle oder der Datenquellen
Erstellen der Abfrage
Ausführen der Abfrage
In LINQ sind die Ausführung einer Abfrage und die Erstellung der Abfrage voneinander getrennte Vorgänge. Sie rufen Daten nicht einfach ab, indem Sie eine Abfrage erstellen. Dieser Punkt wird weiter unten in diesem Thema ausführlich erläutert.
Im folgenden Beispiel werden die drei Teile einer Abfrageoperation veranschaulicht. Im Beispiel wird ein Array von Ganzzahlen als zweckmäßige Datenquelle zur Demonstration der Vorgehensweise verwendet. Dieselben Konzepte gelten jedoch auch für andere Datenquellen.
' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}
' Query creation.
Dim evensQuery = From num In numbers _
Where num Mod 2 = 0 _
Select num
' Query execution.
For Each number In evensQuery
Console.Write(number & " ")
Next
Ausgabe:
0 2 4 6
Die Datenquelle
Da es sich bei der Datenquelle im vorherigen Beispiel um ein Array handelt, unterstützt sie implizit die generische IEnumerable<T>-Schnittstelle. Dadurch kann ein Array als Datenquelle für eine LINQ-Abfrage verwendet werden. Typen, die IEnumerable(Of T) unterstützen oder eine abgeleitete Schnittstelle, wie z. B. der generische Typ IQueryable<T>, werden als abfragbare Typen bezeichnet.
Da das Array ein abfragbarer Typ ist, ist keine Änderung oder besondere Behandlung erforderlich, um es als LINQ-Datenquelle zu verwenden. Dies gilt auch für alle Auflistungstypen, die IEnumerable(Of T) unterstützen, einschließlich des generischen Typs List<T>, Dictionary<TKey, TValue> und anderer Klassen der .NET Framework-Klassenbibliothek.
Wenn IEnumerable(Of T) nicht bereits in die Datenquelle implementiert ist, wird ein LINQ-Anbieter benötigt, der die Funktionen der Standardabfrageoperatoren für diese Datenquelle implementiert. So übernimmt beispielsweise LINQ to XML die Aufgabe, ein XML-Dokument in einen abfragbaren XElement-Typ zu laden, wie im folgenden Beispiel dargestellt. Weitere Informationen über Standardabfrageoperatoren finden Sie unter Übersicht über Standardabfrageoperatoren.
' Create a data source from an XML document.
Dim contacts As XElement = XElement.Load("c:\myContactList.xml")
Mit LINQ to SQL erstellen Sie zuerst eine objektrelationale Zuordnung zur Entwurfszeit, entweder manuell oder über Object Relational Designer (O/R-Designer). Sie schreiben die Abfragen anhand der Objekte, und zur Laufzeit übernimmt LINQ to SQL die Kommunikation mit der Datenbank. Im folgenden Beispiel stellt customers eine bestimmte Tabelle in der Datenbank dar, und Table<TEntity> unterstützt die generische IQueryable<T>.
' Create a data source from a SQL table.
Dim db As New DataContext("C:\Northwind\Northwnd.mdf")
Dim customers As Table(Of Customer) = db.GetTable(Of Customer)
Weitere Informationen zum Erstellen bestimmter Typen von Datenquellen finden Sie in der Dokumentation der verschiedenen LINQ-Anbieter. (Eine Liste dieser Anbieter finden Sie unter Sprachintegrierte Abfrage (Language-Integrated Query, LINQ).) Die Grundregel ist einfach: Eine LINQ-Datenquelle ist jedes Objekt, das die generische IEnumerable<T>-Schnittstelle oder eine Schnittstelle unterstützt, die von ihr erbt.
Hinweis: |
---|
Typen wie ArrayList, die die nicht generische IEnumerable-Schnittstelle unterstützen, können ebenso als LINQ-Datenquellen verwendet werden. Ein Beispiel, in dem eine ArrayList verwendet wird, finden Sie unter Gewusst wie: Abfragen von ArrayList mit LINQ. |
Die Abfrage
In der Abfrage geben Sie an, welche Informationen Sie aus der Datenquelle oder den Datenquellen abrufen möchten. Sie haben auch die Möglichkeit, anzugeben, wie diese Informationen vor der Rückgabe sortiert, gruppiert oder strukturiert werden sollen. Um das Erstellen von Abfragen zu ermöglichen, wurde eine neue Abfragesyntax in die Visual Basic-Sprache integriert.
Wenn die Abfrage im folgenden Beispiel ausgeführt wird, gibt sie alle geraden Zahlen aus einem Ganzzahlen-Array, numbers, zurück.
' Data source.
Dim numbers() As Integer = {0, 1, 2, 3, 4, 5, 6}
' Query creation.
Dim evensQuery = From num In numbers _
Where num Mod 2 = 0 _
Select num
' Query execution.
For Each number In evensQuery
Console.Write(number & " ")
Next
Der Abfrageausdruck enthält drei Klauseln: From, Where und Select. Die spezielle Funktion und der Zweck jeder Abfrageausdrucksklausel werden in Grundlegende Abfrageoperationen (Visual Basic) erläutert. Weitere Informationen finden Sie unter Abfragen (Visual Basic). Beachten Sie, dass in LINQ eine Abfragedefinition häufig in einer Variablen gespeichert und später ausgeführt wird. Die Abfragevariable, z. B. evensQuery im vorherigen Beispiel, muss ein abfragbarer Typ sein. evensQuery gehört zum Typ IEnumerable(Of Integer), der vom Compiler unter Verwendung des lokalen Typrückschlusses zugewiesen wird.
Beachten Sie, dass die Abfragevariable selbst keine Aktion ausführt und keine Daten zurückgibt. Sie speichert nur die Abfragedefinition. Im vorherigen Beispiel wird die Abfrage durch die For Each-Schleife ausgeführt.
Abfrageausführung
Die Ausführung einer Abfrage erfolgt getrennt von der Erstellung einer Abfrage. Beim Erstellen der Abfrage wird die Abfrage definiert. Das Ausführen wird jedoch durch einen anderen Mechanismus ausgelöst. Eine Abfrage kann ausgeführt werden, sobald sie definiert ist (unmittelbare Ausführung), oder die Definition kann gespeichert und die Abfrage später ausgeführt werden (verzögerte Ausführung).
Verzögerte Ausführung
Eine typische LINQ-Abfrage sieht ähnlich der Abfrage im vorherigen Beispiel aus, in dem evensQuery definiert wird. Dabei wird die Abfrage erstellt, jedoch nicht sofort ausgeführt. Stattdessen wird die Abfragedefinition in der Abfragevariablen evensQuery gespeichert. Die Abfrage wird später ausgeführt, in der Regel unter Verwendung einer For Each-Schleife, die eine Sequenz von Werten zurückgibt, oder durch Anwendung eines Standardabfrageoperators wie Count oder Max. Dieser Vorgang wird als verzögerte Ausführung bezeichnet.
' Query execution that results in a sequence of values.
For Each number In evensQuery
Console.Write(number & " ")
Next
' Query execution that results in a single value.
Dim evens = evensQuery.Count()
Bei einer Sequenz von Werten greifen Sie auf die abgerufenen Daten unter Verwendung der Iterationsvariablen in der For Each-Schleife zu (im vorherigen Beispiel number). Da die Abfragevariable evensQuery die Abfragedefinition und nicht die Abfrageergebnisse enthält, können Sie die Abfrage beliebig oft ausführen, indem Sie die Abfragevariable mehrfach verwenden. Sie könnten beispielsweise über eine Datenbank in Ihrer Anwendung verfügen, die ständig durch eine separate Anwendung aktualisiert wird. Nach Erstellen einer Abfrage, mit der Daten aus dieser Datenbank abgerufen werden, können Sie eine For Each-Schleife verwenden, um die Abfrage wiederholt auszuführen, sodass jedes Mal die neuesten Daten abgerufen werden.
Das folgende Beispiel veranschaulicht die Funktionsweise der verzögerten Ausführung. Nachdem evensQuery2 definiert und mit einer For Each-Schleife ausgeführt wurde, wie in den vorherigen Beispielen, ändern sich einige Elemente in der Datenquelle numbers. Anschließend führt eine zweite For Each-Schleife erneut evensQuery2 aus. Beim zweiten Mal sind die Ergebnisse anders, da die For Each-Schleife die Abfrage erneut ausführt, und zwar unter Verwendung der neuen Werte in numbers.
Dim numberArray() As Integer = {0, 1, 2, 3, 4, 5, 6}
Dim evensQuery2 = From num In numberArray _
Where num Mod 2 = 0 _
Select num
Console.WriteLine("Evens in original array:")
For Each number In evensQuery2
Console.Write(" " & number)
Next
Console.WriteLine()
' Change a few array elements.
numberArray(1) = 10
numberArray(4) = 22
numberArray(6) = 8
' Run the same query again.
Console.WriteLine(vbCrLf & "Evens in changed array:")
For Each number In evensQuery2
Console.Write(" " & number)
Next
Console.WriteLine()
Ausgabe:
Evens in original array:
0 2 4 6
Evens in changed array:
0 10 2 22 8
Unmittelbare Ausführung
Bei der verzögerten Ausführung von Abfragen wird die Abfragedefinition für die spätere Ausführung in einer Abfragevariablen gespeichert. Bei der unmittelbaren Ausführung wird die Abfrage zum Zeitpunkt ihrer Definition ausgeführt. Die Abfrage wird ausgelöst, indem Sie eine Methode anwenden, für die ein Zugriff auf einzelne Elemente des Abfrageergebnisses erforderlich ist. Die unmittelbare Ausführung wird häufig durch die Verwendung eines der Standardabfrageoperatoren erzwungen, die einzelne Werte zurückgeben. Beispiele sind Count, Max, Average und First. Diese Standardabfrageoperatoren führen die Abfrage aus, sobald sie angewendet werden, um ein einzelnes Ergebnis zu berechnen und zurückzugeben. Weitere Informationen über Standardabfrageoperatoren, die einzelne Werte zurückgeben, finden Sie unter Aggregationsoperationen, Elementvorgänge und Quantifiziereroperationen.
Die folgende Abfrage gibt die Anzahl der geraden Zahlen in einem Ganzzahlen-Array zurück. Die Abfragedefinition wird nicht gespeichert, und numEvens ist eine einfache Integer.
Dim numEvens = (From num In numbers _
Where num Mod 2 = 0 _
Select num).Count()
Das gleiche Ergebnis lässt sich mithilfe der Aggregate-Methode erzielen.
Dim numEvensAgg = Aggregate num In numbers _
Where num Mod 2 = 0 _
Select num _
Into Count()
Sie können die Ausführung einer Abfrage auch erzwingen, indem Sie die ToList- oder die ToArray-Methode für eine Abfrage (unmittelbar) oder eine Abfragevariable (verzögert) aufrufen, wie im folgenden Code gezeigt.
' Immediate execution.
Dim evensList = (From num In numbers _
Where num Mod 2 = 0 _
Select num).ToList()
' Deferred execution.
Dim evensQuery3 = From num In numbers _
Where num Mod 2 = 0 _
Select num
' . . .
Dim evensArray = evensQuery.ToArray()
In den vorherigen Beispielen ist evensQuery3 eine Abfragevariable, evensList ist jedoch eine Liste, und evensArray ist ein Array.
Die Verwendung von ToList oder ToArray zum Erzwingen einer unmittelbaren Ausführung ist besonders nützlich in Szenarien, in denen Sie die Abfrage sofort ausführen und die Ergebnisse in einem einzigen Auflistungsobjekt zwischenspeichern möchten. Weitere Informationen über diese Methoden finden Sie unter Konvertieren von Datentypen.
Sie können das Ausführen einer Abfrage auch durch Verwendung einer IEnumerable-Methode veranlassen, z. B. die GetEnumerator-Methode (Collection-Objekt).
Siehe auch
Aufgaben
Beispielabfragen (Visual Basic)
Konzepte
Übersicht über den O/R-Designer
Übersicht über Standardabfrageoperatoren
Einführung in LINQ in Visual Basic