Datentransformationen mit LINQ

Aktualisiert: November 2007

Sprachintegrierte Abfrage (Language-Integrated Query, LINQ) dient nicht nur zum Abrufen von Daten. Es ist auch ein leistungsstarkes Tool zum Transformieren von Daten. Mit einer LINQ-Abfrage können Sie eine Quellsequenz als Eingabe verwenden und sie auf verschiedene Art und Weise zum Erstellen einer neuen Ausgabesequenz einsetzen. Sie können die Sequenz durch Sortieren und Gruppieren ändern, ohne die Elemente zu ändern. Das vielleicht leistungsstärkste Feature von LINQ-Abfragen ist die Fähigkeit, neue Typen zu erstellen. Dies wird mit der select-Klausel erreicht. Sie können z. B. folgende Aufgaben ausführen:

  • Führen Sie mehrere Eingabesequenzen in eine einzelne Ausgabesequenz zusammen, die einen neuen Typ hat.

  • Erstellen Sie Ausgabesequenzen, deren Elemente aus nur einer oder mehreren Eigenschaften jedes Elements in der Quellsequenz bestehen.

  • Erstellen Sie Ausgabesequenzen, deren Elemente aus den Ergebnissen von Operationen bestehen, die für die Quelldaten ausgeführt werden.

  • Erstellen Sie Ausgabesequenzen in einem anderen Format. Zum Beispiel können Sie Daten von SQL-Zeilen oder Textdateien in XML umwandeln.

Dies sind nur einige Beispiele. Natürlich können diese Transformationen auf verschiedene Art und Weise in der gleichen Abfrage kombiniert werden. Außerdem kann die Ausgabesequenz einer Abfrage als Eingabesequenz für eine neue Abfrage verwendet werden.

Verknüpfen mehrerer Eingaben in eine Ausgabesequenz

Sie können eine LINQ-Abfrage zum Erstellen einer Ausgabesequenz verwenden, die Elemente von mehr als einer Eingabesequenz enthält. Im folgenden Beispiel wird gezeigt, wie zwei Datenstrukturen im Speicher kombiniert werden, aber die gleichen Prinzipien können für die Kombination von XML- oder SQL- oder DataSet-Quellen angewendet werden. Nehmen wir an, es liegen die folgenden beiden Klassentypen vor:

class Student
{
    public string First { get; set; }
    public string Last {get; set;}
    public int ID { get; set; }
    public string Street { get; set; }
    public string City { get; set; }
    public List<int> Scores;
}

class Teacher
{
    public string First { get; set; }
    public string Last { get; set; }
    public int ID { get; set; } 
    public string City { get; set; }
}

Im folgenden Beispiel wird die Abfrage gezeigt:

class DataTransformations
{
    static void Main()
    {
        // Create the first data source.
        List<Student> students = new List<Student>()
        {
            new Student {First="Svetlana",
                Last="Omelchenko", 
                ID=111, 
                Street="123 Main Street",
                City="Seattle",
                Scores= new List<int> {97, 92, 81, 60}},
            new Student {First="Claire",
                Last="O’Donnell", 
                ID=112,
                Street="124 Main Street",
                City="Redmond",
                Scores= new List<int> {75, 84, 91, 39}},
            new Student {First="Sven",
                Last="Mortensen",
                ID=113,
                Street="125 Main Street",
                City="Lake City",
                Scores= new List<int> {88, 94, 65, 91}},
        };

        // Create the second data source.
        List<Teacher> teachers = new List<Teacher>()
        {                
            new Teacher {First="Ann", Last="Beebe", ID=945, City = "Seattle"},
            new Teacher {First="Alex", Last="Robinson", ID=956, City = "Redmond"},
            new Teacher {First="Michiyo", Last="Sato", ID=972, City = "Tacoma"}
        };

        // Create the query.
        var peopleInSeattle = (from student in students
                    where student.City == "Seattle"
                    select student.Last)
                    .Concat(from teacher in teachers
                            where teacher.City == "Seattle"
                            select teacher.Last);

        Console.WriteLine("The following students and teachers live in Seattle:");
        // Execute the query.
        foreach (var person in peopleInSeattle)
        {
            Console.WriteLine(person);
        }

        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    The following students and teachers live in Seattle:
    Omelchenko
    Beebe
 */

Weitere Informationen finden Sie unter join-Klausel (C#-Referenz) und unter select-Klausel (C#-Referenz).

Auswählen einer Teilmenge jedes Quellelements

Es gibt zwei primäre Möglichkeiten, in der Quellsequenz eine Teilmenge von jedem Element auszuwählen:

  1. Um nur einen Member des Quellelements auszuwählen, verwenden Sie die Punktoperation. Im folgenden Beispiel wird davon ausgegangen, dass ein Customer-Objekt verschiedene öffentliche Eigenschaften enthält, einschließlich der Zeichenfolge City. Bei Ausführung erzeugt diese Abfrage eine Ausgabesequenz von Zeichenfolgen.

    var query = from cust in Customers
                select cust.City;
    
  2. Um Elemente zu erstellen, die mehr als eine Eigenschaft vom Quellelement enthalten, können Sie einen Objektinitialisierer mit einem benannten Objekt oder einem anonymen Typ verwenden. Im folgenden Beispiel wird die Verwendung eines anonymen Typs zum Kapseln zweier Eigenschaften von jedem Customer-Element veranschaulicht:

    var query = from cust in Customer
                select new {Name = cust.Name, City = cust.City};
    

Weitere Informationen finden Sie unter Objekt- und Auflistungsinitialisierer (C#-Programmierhandbuch) und unter Anonyme Typen (C#-Programmierhandbuch).

Transformieren von Objekten im Speicher in XML

Mit LINQ-Abfragen können Daten zwischen Datenstrukturen im Speicher, SQL-Datenbanken, ADO.NET-Datasets und XML-Streams oder -Dokumenten auf einfache Weise umgewandelt werden. Im folgenden Beispiel werden Objekte in einer Datenstruktur im Speicher in XML-Elemente umgewandelt.

class XMLTransform
{
    static void Main()
    {            
        // Create the data source by using a collection initializer.
        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}},
        };

        // Create the query.
        var studentsToXML = new XElement("Root",
            from student in students
            let x = String.Format("{0},{1},{2},{3}", student.Scores[0],
                    student.Scores[1], student.Scores[2], student.Scores[3])
            select new XElement("student",
                       new XElement("First", student.First),
                       new XElement("Last", student.Last),
                       new XElement("Scores", x)
                    ) // end "student"
                ); // end "Root"

        // Execute the query.
        Console.WriteLine(studentsToXML);

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}

Der Code erzeugt die folgende XML-Ausgabe:

< Root>
  <student>
    <First>Svetlana</First>
    <Last>Omelchenko</Last>
    <Scores>97,92,81,60</Scores>
  </student>
  <student>
    <First>Claire</First>
    <Last>O'Donnell</Last>
    <Scores>75,84,91,39</Scores>
  </student>
  <student>
    <First>Sven</First>
    <Last>Mortensen</Last>
    <Scores>88,94,65,91</Scores>
  </student>
</Root>

Weitere Informationen finden Sie unter Erstellen von XML-Strukturen in C# (LINQ to XML).

Ausführen von Operationen für Quellelemente

Eine Ausgabesequenz enthält unter Umständen keine Elemente oder Elementeigenschaften aus der Quellsequenz. Diese Ausgabe kann stattdessen eine Wertesequenz sein, die durch Verwendung der Quellelemente als Eingabeargumente berechnet wird. Durch folgende einfache Abfrage wird eine Zeichenfolgensequenz ausgegeben, deren Werte eine Berechnung basierend auf der Quellelementsequenz des Typs double darstellen.

Hinweis:

Das Aufrufen von Methoden in Abfrageausdrücken wird nicht unterstützt, wenn die Abfrage für eine andere Domäne übersetzt wird. Sie können beispielsweise keine normale C#-Methode in LINQ to SQL aufrufen, da SQL Server über keinen Kontext dafür verfügt. Sie können jedoch gespeicherte Prozeduren Methoden zuordnen und diese aufrufen. Weitere Informationen finden Sie unter Gespeicherte Prozeduren (LINQ to SQL).

class FormatQuery
{
    static void Main()
    {            
        // Data source.
        double[] radii = { 1, 2, 3 };

        // Query.
        IEnumerable<string> query =
            from rad in radii
            select String.Format("Area = {0}", (rad * rad) * 3.14);

        // Query execution. 
        foreach (string s in query)
            Console.WriteLine(s);

        // Keep the console open in debug mode.
        Console.WriteLine("Press any key to exit.");
        Console.ReadKey();
    }
}
/* Output:
    Area = 3.14
    Area = 12.56
    Area = 28.26
*/

Siehe auch

Konzepte

LINQ-Abfrageausdrücke (C#-Programmierhandbuch)

Referenz

select-Klausel (C#-Referenz)

Weitere Ressourcen

Sprachintegrierte Abfrage (Language-Integrated Query, LINQ)

LINQ to SQL

LINQ to DataSet

LINQ to XML