Walkthrough: Writing Queries in C# (LINQ)

 

Die neueste Dokumentation zu Visual Studio 2017 RC finden Sie unter Visual Studio 2017 RC Documentation (Dokumentation zu Visual Studio 2017 RC).

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.

Diese exemplarische Vorgehensweise erfordert Funktionen, die in Visual Studio 2008.

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

So erstellen Sie ein Projekt

  1. Starten Sie Visual Studio.

  2. Wählen Sie in der Menüleiste Datei, Neu, Projekt aus.

    Das Dialogfeld Neues Projekt wird angezeigt.

  3. Erweitern Sie InstalliertVorlagen, erweitern Sie, erweitern Sie Visual C# und wählen Sie dann Konsolenanwendung aus.

  4. Im Name Textfeld geben Sie einen anderen Namen ein oder übernehmen Sie den Standardnamen, und wählen Sie dann die Schaltfläche OK aus.

    Das neue Projekt wird im Projektmappen-Explorer angezeigt.

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

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 ins 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 und Objekt- und Auflistungsinitialisierer.

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

  1. 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.

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.)

    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;

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);
            }

            // Output:
            // Omelchenko, Svetlana
            // Garcia, Cesar
            // Fakhouri, Fadi
            // Feng, Hanying
            // Garcia, Hugo
            // Adams, Terry
            // Zabokritski, Eugene
            // Tucker, Michael

So fügen Sie eine weitere Filterbedingung hinzu

  1. 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.

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.

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);
                    }
                }
    
                // Output:
                // O
                //   Omelchenko, Svetlana
                //   O'Donnell, Claire
                // M
                //   Mortensen, Sven
                // G
                //   Garcia, Cesar
                //   Garcia, Debra
                //   Garcia, Hugo
                // F
                //   Fakhouri, Fadi
                //   Feng, Hanying
                // T
                //   Tucker, Lance
                //   Tucker, Michael
                // A
                //   Adams, Terry
                // Z
                //   Zabokritski, Eugene
    

  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.

So machen Sie die Variablen zu implizit typisierten Variablen

  1. 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 die Iteration Variable group zu var und überprüfen Sie die Abfrage. 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);
                    }
                }
    
                // Output:
                // O
                //   Omelchenko, Svetlana
                //   O'Donnell, Claire
                // M
                //   Mortensen, Sven
                // G
                //   Garcia, Cesar
                //   Garcia, Debra
                //   Garcia, Hugo
                // F
                //   Fakhouri, Fadi
                //   Feng, Hanying
                // T
                //   Tucker, Lance
                //   Tucker, Michael
                // A
                //   Adams, Terry
                // Z
                //   Zabokritski, Eugene
    

    Weitere Informationen über var finden Sie unter Implizit typisierte lokale Variablen.

So sortieren Sie die Gruppen nach ihrem Schlüsselwert

  1. 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);
                    }
                }
    
                // Output:
                //A
                //   Adams, Terry
                //F
                //   Fakhouri, Fadi
                //   Feng, Hanying
                //G
                //   Garcia, Cesar
                //   Garcia, Debra
                //   Garcia, Hugo
                //M
                //   Mortensen, Sven
                //O
                //   Omelchenko, Svetlana
                //   O'Donnell, Claire
                //T
                //   Tucker, Lance
                //   Tucker, Michael
                //Z
                //   Zabokritski, Eugene
    

    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

  1. 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);
                }
    
                // Output:
                // Omelchenko Svetlana
                // O'Donnell Claire
                // Mortensen Sven
                // Garcia Cesar
                // Fakhouri Fadi
                // Feng Hanying
                // Garcia Hugo
                // Adams Terry
                // Zabokritski Eugene
                // Tucker Michael
    

    Weitere Informationen finden Sie unter let-Klausel.

So verwenden Sie Methodensyntax in einem Abfrageausdruck

  1. Wie in Query Syntax and Method Syntax in LINQ 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);
    
                // Output:
                // Class average score = 334.166666666667
    

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);
                }
    
                // Output:
                // The Garcias in the class are:
                // Cesar
                // Debra
                // Hugo
    

  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);
                }
    
                // Output:
                // Student ID: 113, Score: 338
                // Student ID: 114, Score: 353
                // Student ID: 116, Score: 369
                // Student ID: 117, Score: 352
                // Student ID: 118, Score: 343
                // Student ID: 120, Score: 341
                // Student ID: 122, Score: 368
    

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 to Objects

LINQ (Language-Integrated Query)
Getting Started with LINQ in C#
LINQ-Abfrageausdrücke
Supplementary LINQ Resources
Exemplarische Vorgehensweise: Schreiben von Abfragen in Visual Basic

Anzeigen: