Einführung in LINQ-Abfragen (C#)Introduction to LINQ Queries (C#)

Eine Abfrage ist ein Ausdruck, der Daten von einer Datenquelle abruft.A query is an expression that retrieves data from a data source. Abfragen werden normalerweise in einer spezialisierten Abfragesprache ausgedrückt.Queries are usually expressed in a specialized query language. Im Laufe der Zeit wurden verschiedene Sprachen für die verschiedenen Datenquellen entwickelt, beispielsweise SQL für relationale Datenbanken und XQuery für XML.Different languages have been developed over time for the various types of data sources, for example SQL for relational databases and XQuery for XML. Aus diesem Grund mussten Entwickler für jeden Typ von Datenquelle oder Datenformat, den sie unterstützen müssen, eine neue Abfragesprache erlernen.Therefore, developers have had to learn a new query language for each type of data source or data format that they must support. LINQLINQ vereinfacht diese Situation durch die Bereitstellung eines konsistenten Modells zum Arbeiten mit Daten in verschiedenen Arten von Datenquellen und Formaten. simplifies this situation by offering a consistent model for working with data across various kinds of data sources and formats. In einer LINQLINQ-Abfrage arbeiten Sie immer mit Objekten.In a LINQLINQ query, you are always working with objects. Sie verwenden dieselben grundlegenden Codierungsmuster für die Abfrage und Transformation von Daten in XML-Dokumenten, SQL-Datenbanken, ADO.NETADO.NET-Datasets, .NET-Auflistungen sowie allen anderen Quellen und Formaten, für die ein LINQLINQ-Anbieter verfügbar ist.You use the same basic coding patterns to query and transform data in XML documents, SQL databases, ADO.NETADO.NET Datasets, .NET collections, and any other format for which a LINQLINQ provider is available.

Drei Teile einer AbfrageoperationThree Parts of a Query Operation

Alle LINQLINQ-Abfrageoperationen bestehen aus drei unterschiedlichen Aktionen:All LINQLINQ query operations consist of three distinct actions:

  1. Abrufen der DatenquelleObtain the data source.

  2. Erstellen der AbfrageCreate the query.

  3. Ausführen der AbfrageExecute the query.

Im folgenden Beispiel wird gezeigt, wie die drei Teile einer Abfrageoperation in Quellcode ausgedrückt werden.The following example shows how the three parts of a query operation are expressed in source code. Das Beispiel verwendet aus praktischen Gründen ein Array von Ganzzahlen als Datenquelle. Dieselben Konzepte gelten jedoch auch für andere Datenquellen.The example uses an integer array as a data source for convenience; however, the same concepts apply to other data sources also. Auf dieses Beispiel wird im Rest dieses Themas Bezug genommen.This example is referred to throughout the rest of this topic.

class IntroToLINQ
{        
    static void Main()
    {
        // The Three Parts of a LINQ Query:
        //  1. Data source.
        int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };

        // 2. Query creation.
        // numQuery is an IEnumerable<int>
        var numQuery =
            from num in numbers
            where (num % 2) == 0
            select num;

        // 3. Query execution.
        foreach (int num in numQuery)
        {
            Console.Write("{0,1} ", num);
        }
    }
}

Die folgende Abbildung zeigt die vollständige Abfrageoperation.The following illustration shows the complete query operation. In LINQLINQ unterscheidet sich die Ausführung der Abfrage von der Abfrage selbst, oder anders ausgedrückt: Durch das bloße Erstellen einer Abfragevariablen werden keine Daten abgefragt.In LINQLINQ the execution of the query is distinct from the query itself; in other words you have not retrieved any data just by creating a query variable.

Vollständiger LINQ-AbfragevorgangComplete LINQ Query Operation

Die DatenquelleThe Data Source

Da es sich bei der Datenquelle im vorherigen Beispiel um ein Array handelt, unterstützt sie implizit die generische IEnumerable<T>-Schnittstelle.In the previous example, because the data source is an array, it implicitly supports the generic IEnumerable<T> interface. Das bedeutet, dass sie mit LINQLINQ abgefragt werden kann.This fact means it can be queried with LINQLINQ. Eine Abfrage wird in einer foreach-Anweisung ausgeführt, und foreach erfordert IEnumerable oder IEnumerable<T>.A query is executed in a foreach statement, and foreach requires IEnumerable or IEnumerable<T>. Typen, die IEnumerable<T> unterstützen oder eine abgeleitete Schnittstelle, wie z.B. der generische Typ IQueryable<T>, werden als abfragbare Typen bezeichnet.Types that support IEnumerable<T> or a derived interface such as the generic IQueryable<T> are called queryable types.

Für abfragbare Typen ist keine Änderung oder besondere Behandlung notwendig, um sie als LINQLINQ-Datenquelle zu verwenden.A queryable type requires no modification or special treatment to serve as a LINQLINQ data source. Wenn die Quelldaten nicht bereits als abfragbarer Typ im Arbeitsspeicher vorhanden sind, muss der LINQLINQ-Anbieter diese als solcher darstellen.If the source data is not already in memory as a queryable type, the LINQLINQ provider must represent it as such. Zum Beispiel lädt LINQ to XML ein XML-Dokument in einen abfragbaren XElement-Typ:For example, LINQ to XML loads an XML document into a queryable XElement type:

// Create a data source from an XML document.
// using System.Xml.Linq;
XElement contacts = XElement.Load(@"c:\myContactList.xml");

Mit LINQ to SQLLINQ to SQL erstellen Sie zuerst eine objektrelationale Zuordnung zur Entwurfszeit, entweder manuell oder mit den LING in SQL-Tools in Visual Studio.With LINQ to SQLLINQ to SQL, you first create an object-relational mapping at design time either manually or by using the LINQ to SQL Tools in Visual Studio in Visual Studio. Sie schreiben die Abfragen anhand der Objekte, und zur Laufzeit übernimmt LINQ to SQLLINQ to SQL die Kommunikation mit der Datenbank.You write your queries against the objects, and at run-time LINQ to SQLLINQ to SQL handles the communication with the database. Im folgenden Beispiel stellt Customers eine bestimmte Tabelle in der Datenbank dar, und der Typ des Abfrageergebnisses, IQueryable<T>, wird von IEnumerable<T> abgeleitet.In the following example, Customers represents a specific table in the database, and the type of the query result, IQueryable<T>, derives from IEnumerable<T>.

Northwnd db = new Northwnd(@"c:\northwnd.mdf");  

// Query for customers in London.  
IQueryable<Customer> custQuery =  
    from cust in db.Customers  
    where cust.City == "London"  
    select cust;  

Weitere Informationen zum Erstellen bestimmter Typen von Datenquellen finden Sie in der Dokumentation der verschiedenen LINQLINQ-Anbieter.For more information about how to create specific types of data sources, see the documentation for the various LINQLINQ providers. Die Grundregel ist jedoch sehr einfach: Eine LINQLINQ-Datenquelle ist jedes Objekt, das die generische IEnumerable<T>-Schnittstelle oder eine Schnittstelle unterstützt, die davon erbt.However, the basic rule is very simple: a LINQLINQ data source is any object that supports the generic IEnumerable<T> interface, or an interface that inherits from it.

Hinweis

Typen wie ArrayList, die die nicht generische IEnumerable-Schnittstelle unterstützen, können ebenso als LINQLINQ-Datenquelle verwendet werden.Types such as ArrayList that support the non-generic IEnumerable interface can also be used as a LINQLINQ data source. Weitere Informationen finden Sie unter Vorgehensweise: Abfragen von ArrayList mit LINQ (C#).For more information, see How to: Query an ArrayList with LINQ (C#).

Die AbfrageThe Query

Die Abfrage gibt an, welche Informationen aus der Datenquelle oder den Datenquellen abgerufen werden sollen.The query specifies what information to retrieve from the data source or sources. Optional kann eine Abfrage auch angeben, wie diese Informationen vor der Rückgabe sortiert, gruppiert und strukturiert werden sollen.Optionally, a query also specifies how that information should be sorted, grouped, and shaped before it is returned. Eine Abfrage wird in einer Abfragevariablen gespeichert und mit einem Abfrageausdruck initialisiert.A query is stored in a query variable and initialized with a query expression. Um das Schreiben von Abfragen zu erleichtern, hat C# eine neue Abfragesyntax eingeführt.To make it easier to write queries, C# has introduced new query syntax.

Die Abfrage im vorherigen Beispiel gibt alle geraden Zahlen aus einem Ganzzahlen-Array zurück.The query in the previous example returns all the even numbers from the integer array. Der Abfrageausdruck enthält drei Klauseln: from, where und select.The query expression contains three clauses: from, where and select. (Wenn Sie mit SQL vertraut sind, ist Ihnen wahrscheinlich aufgefallen, dass die Klauseln umgekehrt wie in SQL angeordnet sind.) Die from-Klausel gibt die Datenquelle an, die where-Klausel wendet den Filter an, und die select-Klausel gibt den Typ der zurückgegebenen Elemente an.(If you are familiar with SQL, you will have noticed that the ordering of the clauses is reversed from the order in SQL.) The from clause specifies the data source, the where clause applies the filter, and the select clause specifies the type of the returned elements. Diese und weitere Abfrageklauseln werden ausführlich im Abschnitt LINQ-Abfrageausdrücke erläutert.These and the other query clauses are discussed in detail in the LINQ Query Expressions section. Wichtig ist hier, dass die Abfragevariable selbst in LINQLINQ keine Aktion ausführt und keine Daten zurückgibt.For now, the important point is that in LINQLINQ, the query variable itself takes no action and returns no data. Sie speichert nur die Informationen, die erforderlich sind, um Ergebnisse zu erzeugen, wenn die Abfrage zu einem späteren Zeitpunkt ausgeführt wird.It just stores the information that is required to produce the results when the query is executed at some later point. Weitere Informationen zum Erstellen von Abfragen hinter den Kulissen finden Sie unter Übersicht über Standardabfrageoperatoren (C#).For more information about how queries are constructed behind the scenes, see Standard Query Operators Overview (C#).

Hinweis

Abfragen können auch unter Verwendung der Methodensyntax ausgedrückt werden.Queries can also be expressed by using method syntax. Weitere Informationen finden Sie unter Abfragesyntax und Methodensyntax in LINQ.For more information, see Query Syntax and Method Syntax in LINQ.

AbfrageausführungQuery Execution

Verzögerte AusführungDeferred Execution

Wie bereits erwähnt, speichert die Abfragevariable selbst nur die Abfragebefehle.As stated previously, the query variable itself only stores the query commands. Die tatsächliche Ausführung der Abfrage wird so lange verzögert, bis Sie die Abfragevariable in einer foreach-Anweisung durchlaufen.The actual execution of the query is deferred until you iterate over the query variable in a foreach statement. Dieses Konzept wird als verzögerte Ausführung bezeichnet und wird im folgenden Beispiel veranschaulicht:This concept is referred to as deferred execution and is demonstrated in the following example:

//  Query execution. 
foreach (int num in numQuery)
{
    Console.Write("{0,1} ", num);
}

In der foreach-Anweisung werden auch die Abfrageergebnisse abgerufen.The foreach statement is also where the query results are retrieved. So ist beispielsweise in der vorherigen Abfrage in der Iterationsvariablen num jeder Wert (jeweils einzeln) der zurückgegebenen Sequenz enthalten.For example, in the previous query, the iteration variable num holds each value (one at a time) in the returned sequence.

Da die Abfragevariable selbst nie die Abfrageergebnisse enthält, können Sie sie beliebig oft ausführen.Because the query variable itself never holds the query results, you can execute it as often as you like. Sie könnten beispielsweise über eine Datenbank verfügen, die ständig durch eine separate Anwendung aktualisiert wird.For example, you may have a database that is being updated continually by a separate application. Sie könnten in Ihrer Anwendung eine Abfrage erstellen, die die neuesten Daten abruft, und Sie könnten diese Abfrage in bestimmten Abständen wiederholt ausführen, um bei jeder Ausführung andere Ergebnisse abzurufen.In your application, you could create one query that retrieves the latest data, and you could execute it repeatedly at some interval to retrieve different results every time.

Erzwingen der unmittelbaren AusführungForcing Immediate Execution

Abfragen, die Aggregationsfunktionen für einen Bereich von Quellelementen ausführen, müssen zuerst diese Elemente durchlaufen.Queries that perform aggregation functions over a range of source elements must first iterate over those elements. Beispiele für solche Abfragen sind Count, Max, Average und First.Examples of such queries are Count, Max, Average, and First. Diese Abfragen werden ohne explizite foreach-Anweisung ausgeführt, da die Abfrage selbst foreach verwenden muss, um ein Ergebnis auszugeben.These execute without an explicit foreach statement because the query itself must use foreach in order to return a result. Beachten Sie auch, dass diese Typen von Abfragen einen einzelnen Wert und keine IEnumerable-Auflistung zurückgeben.Note also that these types of queries return a single value, not an IEnumerable collection. Die folgende Abfrage gibt eine Anzahl der geraden Zahlen im Quellarray zurück:The following query returns a count of the even numbers in the source array:

var evenNumQuery = 
    from num in numbers
    where (num % 2) == 0
    select num;

int evenNumCount = evenNumQuery.Count();

Um die unmittelbare Ausführung einer Abfrage zu erzwingen und ihre Ergebnisse zwischenzuspeichern, können Sie die ToList-Methode oder die ToArray-Methode aufrufen.To force immediate execution of any query and cache its results, you can call the ToList or ToArray methods.

List<int> numQuery2 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToList();

// or like this:
// numQuery3 is still an int[]

var numQuery3 =
    (from num in numbers
     where (num % 2) == 0
     select num).ToArray();

Sie können die Ausführung auch erzwingen, indem Sie die foreach-Schleife unmittelbar nach dem Abfrageausdruck setzen.You can also force execution by putting the foreach loop immediately after the query expression. Durch Aufrufen von ToList oder ToArray speichern Sie jedoch auch alle Daten in einem einzelnen Auflistungsobjekt zwischen.However, by calling ToList or ToArray you also cache all the data in a single collection object.

Siehe auchSee Also

Erste Schritte mit LINQ in C#Getting Started with LINQ in C#
Walkthrough (Exemplarische Vorgehensweise: Schreiben von Abfragen in C#)Walkthrough: Writing Queries in C#
Walkthrough (Exemplarische Vorgehensweise: Schreiben von Abfragen in C#)Walkthrough: Writing Queries in C#
LINQ-AbfrageausdrückeLINQ Query Expressions
foreach, inforeach, in
Abfrageschlüsselwörter (LINQ)Query Keywords (LINQ)