Exemplarische Vorgehensweise: Schreiben von Abfragen in C# (LINQ)

Diese exemplarische Vorgehensweise veranschaulicht die C#-Sprachfunktionen, die zum Schreiben von LINQ-Abfrageausdrücken verwendet werden. Nachdem Sie diese exemplarische Vorgehensweise durchgeführt haben, können Sie mit den Beispielen und der Dokumentation für den spezifischen LINQ-Anbieter fortfahren, an dem Sie interessiert sind, beispielsweise LINQ to SQL, LINQ für DataSets oder LINQ to XML.

Vorbereitungsmaßnahmen

Diese exemplarische Vorgehensweise erfordert Visual Studio 2010.

Link zu Video Unter Video How to: Writing Queries in C# (LINQ) finden Sie eine Videoversion dieses Themas.

Erstellen von C#-Projekten

So erstellen Sie ein C#-Projekt, das auf die Version 3.5 von .NET Compact Framework abzielt

  1. Starten Sie Visual Studio.

  2. Zeigen Sie im Menü Datei auf Neu, und klicken Sie dann auf Projekt.

  3. In der rechten oberen Ecke des Dialogfelds Neues Projekt werden drei Symbole angezeigt. Klicken Sie auf das linke Symbol, und stellen Sie sicher, dass .NET Framework, Version 3.5 aktiviert ist.

  4. Klicken Sie auf das Symbol Konsolenanwendung unter Von Visual Studio installierte Vorlagen.

  5. Geben Sie der Anwendung einen neuen Namen, oder übernehmen Sie den Standardnamen, und klicken Sie auf OK.

  6. Beachten Sie, dass das Projekt einen Verweis auf System.Core.dll und eine using-Direktive für den System.Linq-Namespace aufweist.

Erstellen einer Datenquelle im Arbeitsspeicher

Die Datenquelle für die Abfragen ist eine einfache Liste von Student-Objekten. Jeder Student-Datensatz umfasst einen Vornamen, einen Nachnamen und ein Array von Ganzzahlen, dass die Testergebnisse der einzelnen Studenten in der Klasse darstellt. Kopieren Sie diesen Code in das Projekt. Beachten Sie die folgenden Eigenschaften:

  • Die Student-Klasse besteht aus automatisch implementierten Eigenschaften.

  • Jeder Student in der Liste wird mit einem Objektinitialisierer initialisiert.

  • Die Liste selbst wird mit einem Auflistungsinitialisierer initialisiert.

Die gesamte Datenstruktur wird ohne explizite Aufrufe eines Konstruktors oder expliziten Memberzugriff initialisiert und instanziiert. Weitere Informationen über diese neuen Features finden Sie unter Automatisch implementierte Eigenschaften (C#-Programmierhandbuch) und Objekt- und Auflistungsinitialisierer (C#-Programmierhandbuch).

So fügen Sie die Datenquelle hinzu

  • Fügen Sie die Student-Klasse und die initialisierte Liste von Studenten der Program-Klasse im Projekt hinzu.

    public class Student
    {
        public string First { get; set; }
        public string Last { get; set; }
        public int ID { get; set; }
        public List<int> Scores;
    }
    
    // Create a data source by using a collection initializer.
    static List<Student> students = new List<Student>
    {
       new Student {First="Svetlana", Last="Omelchenko", ID=111, Scores= new List<int> {97, 92, 81, 60}},
       new Student {First="Claire", Last="O’Donnell", ID=112, Scores= new List<int> {75, 84, 91, 39}},
       new Student {First="Sven", Last="Mortensen", ID=113, Scores= new List<int> {88, 94, 65, 91}},
       new Student {First="Cesar", Last="Garcia", ID=114, Scores= new List<int> {97, 89, 85, 82}},
       new Student {First="Debra", Last="Garcia", ID=115, Scores= new List<int> {35, 72, 91, 70}},
       new Student {First="Fadi", Last="Fakhouri", ID=116, Scores= new List<int> {99, 86, 90, 94}},
       new Student {First="Hanying", Last="Feng", ID=117, Scores= new List<int> {93, 92, 80, 87}},
       new Student {First="Hugo", Last="Garcia", ID=118, Scores= new List<int> {92, 90, 83, 78}},
       new Student {First="Lance", Last="Tucker", ID=119, Scores= new List<int> {68, 79, 88, 92}},
       new Student {First="Terry", Last="Adams", ID=120, Scores= new List<int> {99, 82, 81, 79}},
       new Student {First="Eugene", Last="Zabokritski", ID=121, Scores= new List<int> {96, 85, 91, 60}},
       new Student {First="Michael", Last="Tucker", ID=122, Scores= new List<int> {94, 92, 91, 91} }
    };
    

So fügen Sie einen neuen Studenten der Liste der Studenten hinzu

  • Fügen Sie einen neuen Student der Students-Liste hinzu, und verwenden Sie einen Namen und Testergebnisse Ihrer Wahl. Versuchen Sie, alle Informationen für den neuen Studenten einzugeben, um die Syntax für den Objektinitialisierer besser kennen zu lernen.

Erstellen der Abfrage

So erstellen Sie eine einfache Abfrage

  • Erstellen Sie in der Main-Methode der Anwendung eine einfache Abfrage, die bei Ausführung eine Liste aller Studenten erzeugt, deren Testergebnis beim ersten Test über 90 lag. Da das gesamte Student-Objekt ausgewählt ist, lautet der Typ der Abfrage IEnumerable<Student>. Obwohl der Code auch eine implizite Typisierung mit dem var-Schlüsselwort verwenden könnte, wird hier die explizite Typisierung verwendet, um die Ergebnisse klar zu veranschaulichen. (Weitere Informationen zu var finden Sie unter Implizit typisierte lokale Variablen (C#-Programmierhandbuch).)

    Die Bereichsvariable der Abfrage student dient als Verweis auf jeden Student in der Quelle und bietet Memberzugriff für jedes Objekt.


// Create the query.
// The first line could also be written as "var studentQuery ="
IEnumerable<Student> studentQuery =
    from student in students
    where student.Scores[0] > 90
    select student;

Ausführen der Abfrage

So führen Sie die Abfrage aus

  1. Schreiben Sie jetzt die foreach-Schleife, die bewirkt, dass die Abfrage ausgeführt wird. Beachten Sie Folgendes im Hinblick auf den Code:

    • Auf jedes Element in der zurückgegebenen Sequenz wird über die Iterationsvariable in der foreach-Schleife zugegriffen.

    • Der Typ dieser Variable ist Student, und der Typ der Abfragevariablen ist kompatibel, IEnumerable<Student>.

  2. Nachdem Sie diesen Code hinzugefügt haben, erstellen Sie die Anwendung und führen sie aus, indem Sie STRG + F5 drücken, um die Ergebnisse im Fenster Konsole anzuzeigen.

// Execute the query.
// var could be used here also.
foreach (Student student in studentQuery)
{
    Console.WriteLine("{0}, {1}", student.Last, student.First);
}

So fügen Sie eine weitere Filterbedingung hinzu

  • Sie können mehrere boolesche Bedingungen in der where-Klausel kombinieren, um eine Abfrage weiter zu verfeinern. Der folgende Code fügt eine Bedingung hinzu, die festlegt, dass die Abfrage nur die Studenten zurückgibt, deren erstes Ergebnis über 90 und deren letztes Ergebnis unter 80 lag. Die where-Klausel sollte etwa folgendermaßen aussehen:

    where student.Scores[0] > 90 && student.Scores[3] < 80
    

    Weitere Informationen finden Sie unter where-Klausel (C#-Referenz).

Ändern der Abfrage

So sortieren Sie die Ergebnisse

  1. Die Ergebnisse lassen sich leichter prüfen, wenn sie sortiert sind. Sie können die zurückgegebene Sequenz nach jedem Feld in den Quellelementen sortieren, auf das zugegriffen werden kann. Die folgende orderby-Klausel sortiert beispielsweise die Ergebnisse anhand des Nachnamens der Studenten alphabetisch von A bis Z. Fügen Sie die folgende orderby-Klausel Ihrer Abfrage hinzu, direkt nach der where-Anweisung und vor der select-Anweisung:

    orderby student.Last ascending
    
  2. Ändern Sie jetzt die orderby-Klausel so, dass die Ergebnisse in umgekehrter Reihenfolge gemäß dem Ergebnis des ersten Tests sortiert werden, vom höchsten Ergebnis zum niedrigsten Ergebnis.

    orderby student.Scores[0] descending
    
  3. Ändern Sie die WriteLine-Formatzeichenfolge, damit Sie die Ergebnisse sehen können:

    Console.WriteLine("{0}, {1} {2}", student.Last, student.First, student.Scores[0]);
    

    Weitere Informationen finden Sie unter orderby-Klausel (C#-Referenz).

So gruppieren Sie die Ergebnisse

  1. Die Gruppierung ist eine leistungsstarke Fähigkeit in Abfrageausdrücken. Eine Abfrage mit einer Gruppenklausel erzeugt eine Sequenz von Gruppen. Jede Gruppe selbst umfasst dabei einen Key und eine Sequenz, die aus allen Membern der Gruppe besteht. Die folgende neue Abfrage gruppiert die Studenten unter Verwendung des Anfangsbuchstabens ihres Nachnamens als Schlüssel.

    // studentQuery2 is an IEnumerable<IGrouping<char, Student>>
    var studentQuery2 =
        from student in students
        group student by student.Last[0];
    
  2. Beachten Sie, dass sich der Typ der Abfrage jetzt geändert hat. Es wird nun eine Sequenz von Gruppen mit einem char-Typ als Schlüssel und einer Sequenz von Student-Objekten erzeugt. Da sich der Typ der Abfrage geändert hat, ändert der folgende Code auch die foreach-Ausführungsschleife:

    // studentGroup is a IGrouping<char, Student>
    foreach (var studentGroup in studentQuery2)
    {
        Console.WriteLine(studentGroup.Key);
        foreach (Student student in studentGroup)
        {
            Console.WriteLine("   {0}, {1}",
                      student.Last, student.First);
        }
    }
    
  3. Drücken Sie STRG + F5, um die Anwendung auszuführen und die Ergebnisse im Fenster Konsole anzuzeigen.

    Weitere Informationen finden Sie unter group-Klausel (C#-Referenz).

So machen Sie die Variablen zu implizit typisierten Variablen

  • Das explizite IEnumerables-Codieren von IGroupings kann rasch zu einer zeitraubenden Aufgabe werden. Sie können die gleiche Abfrage und foreach-Schleife mit weniger Aufwand schreiben, wenn Sie var verwenden. Das var-Schlüsselwort ändert die Typen ihrer Objekte nicht, sondern weist nur den Compiler an, die Typen abzuleiten. Ändern Sie den Typ von studentQuery und den Typ der Iterationsvariablen group in var, und führen Sie die Abfrage erneut aus. Wie Sie sehen, wird die Iterationsvariable in der inneren foreach-Schleife weiterhin als Student typisiert, und die Abfrage funktioniert wie zuvor. Ändern Sie die Iterationsvariable s in var, und führen Sie wieder die Abfrage aus. Sie sehen, dass die Ergebnisse genau gleich sind.

    var studentQuery3 =
        from student in students
        group student by student.Last[0];
    
    foreach (var groupOfStudents in studentQuery3)
    {
        Console.WriteLine(groupOfStudents.Key);
        foreach (var student in groupOfStudents)
        {
             Console.WriteLine("   {0}, {1}",
                 student.Last, student.First);
        }
    }
    

    Weitere Informationen über var finden Sie unter Implizit typisierte lokale Variablen (C#-Programmierhandbuch).

So sortieren Sie die Gruppen nach ihrem Schlüsselwert

  • Wenn Sie die vorherige Abfrage ausführen, stellen Sie fest, dass die Gruppen nicht in alphabetischer Reihenfolge aufgeführt werden. Um dies zu ändern, müssen Sie nach der group-Klausel eine orderby-Klausel bereitstellen. Um eine orderby-Klausel verwenden zu können, benötigen Sie jedoch zuerst einen Bezeichner, der als Verweis auf die durch die group-Klausel erstellten Gruppen dient. Sie stellen den Bezeichner bereit, indem Sie das into-Schlüsselwort wie folgt verwenden:

                var studentQuery4 =
                    from student in students
                    group student by student.Last[0] into studentGroup
                    orderby studentGroup.Key
                    select studentGroup;
    
                foreach (var groupOfStudents in studentQuery4)
                {
                    Console.WriteLine(groupOfStudents.Key);
                    foreach (var student in groupOfStudents)
                    {
                        Console.WriteLine("   {0}, {1}",
                            student.Last, student.First);
                    }
                }
    
    

    Wenn Sie diese Abfrage ausführen, sehen Sie, dass die Gruppen jetzt in alphabetischer Reihenfolge sortiert sind.

So fügen Sie einen Bezeichner mit let ein

  • Sie können das Schlüsselwort let verwenden, um einen Bezeichner für ein Ausdrucksergebnis in den Abfrageausdruck einzubeziehen. Dieser Bezeichner kann aus praktischen Gründen verwendet werden, wie im folgenden Beispiel, oder er kann die Leistung durch Speichern der Ergebnisse eines Ausdrucks verbessern, die ansonsten mehrmals berechnet werden müssten.

    // studentQuery5 is an IEnumerable<string>
    // This query returns those students whose
    // first test score was higher than their
    // average score.
    var studentQuery5 =
        from student in students
        let totalScore = student.Scores[0] + student.Scores[1] +
            student.Scores[2] + student.Scores[3]
        where totalScore / 4 < student.Scores[0]
        select student.Last + " " + student.First;
    
    foreach (string s in studentQuery5)
    {
        Console.WriteLine(s);
    }
    

    Weitere Informationen finden Sie unter let-Klausel (C#-Referenz).

So verwenden Sie Methodensyntax in einem Abfrageausdruck

  • Wie in LINQ-Abfragesyntax und Methodensyntax (C#) beschrieben, können einige Abfrageoperationen nur unter Verwendung von Methodensyntax ausgedrückt werden. Der folgende Code berechnet das Gesamtergebnis für jeden Student in der Quellsequenz und ruft dann die Average()-Methode für die Ergebnisse der Abfrage auf, um das Durchschnittsergebnis der Klasse zu berechnen. Beachten Sie die Platzierung von Klammern rund um den Abfrageausdruck.

        var studentQuery6 = 
            from student in students
            let totalScore = student.Scores[0] + student.Scores[1] +
                student.Scores[2] + student.Scores[3]
            select totalScore;
    
        double averageScore = studentQuery6.Average();
    Console.WriteLine("Class average score = {0}", averageScore);
    

So transformieren oder projizieren Sie in die Select-Klausel

  1. Es kommt sehr häufig vor, dass eine Abfrage eine Sequenz erzeugt, deren Elemente sich von den Elementen in den Quellsequenzen unterscheiden. Löschen Sie ihre vorherige Abfrage und Ausführungsschleife, oder kommentieren Sie sie aus, und ersetzen Sie sie durch den folgenden Code. Beachten Sie, dass die Abfrage eine Sequenz von Zeichenfolgen zurückgibt (keine Students) und dass sich diese Tatsache in der foreach-Schleife widerspiegelt.

                IEnumerable<string> studentQuery7 =
                    from student in students
                    where student.Last == "Garcia"
                    select student.First;
    
                Console.WriteLine("The Garcias in the class are:");
                foreach (string s in studentQuery7)
                {
                    Console.WriteLine(s);
                }
    
    
  2. Der Code weiter oben in dieser exemplarischen Vorgehensweise hat gezeigt, dass das durchschnittliche Klassenergebnis 334 ist. Um eine Sequenz von Students zu erzeugen, deren Ergebnis über dem Klassendurchschnitt liegt, zusammen mit der dazugehörigen Student ID, können Sie einen anonymen Typ in der select-Anweisung verwenden:

                var studentQuery8 =
                    from student in students
                    let x = student.Scores[0] + student.Scores[1] +
                        student.Scores[2] + student.Scores[3]
                    where x > averageScore
                    select new { id = student.ID, score = x };
    
                foreach (var item in studentQuery8)
                {
                    Console.WriteLine("Student ID: {0}, Score: {1}", item.id, item.score);
                }
    
    

Nächste Schritte

Nachdem Sie nun mit den grundlegenden Aspekten der Arbeit mit Abfragen in C# vertraut sind, können Sie die Dokumentation und die Beispiele des spezifischen LINQ-Anbieters lesen, der Sie interessiert:

LINQ to SQL

LINQ to DataSet

LINQ to XML

LINQ-zu-Objekte

Siehe auch

Aufgaben

Exemplarische Vorgehensweise: Schreiben von Abfragen in Visual Basic

Konzepte

LINQ-Abfrageausdrücke (C#-Programmierhandbuch)

Zusätzliche LINQ-Ressourcen

Weitere Ressourcen

LINQ (Language-Integrated Query, sprachintegrierte Abfrage)

Erste Schritte mit LINQ in C#