Trasformazioni dati con LINQ (C#)

LINQ (Language-Integrated Query) non viene utilizzato solo per il recupero dei dati, ma è anche un potente strumento per la trasformazione dei dati. Utilizzando una query LINQ, è possibile utilizzare una sequenza di origine come input e modificarla in molti modi per creare una nuova sequenza di output. È possibile modificare la sequenza senza modificarne gli elementi, ma semplicemente ordinandoli e raggruppandoli. La funzionalità più potente delle query LINQ è costituita probabilmente dalla possibilità di creare nuovi tipi mediante la clausola select. Ad esempio, è possibile effettuare le seguenti attività:

  • Unire più sequenze di input in un'unica sequenza di output contenente un nuovo tipo.

  • Creare sequenze di output i cui elementi sono costituiti da una o più proprietà di ogni elemento presente nella sequenza di origine.

  • Creare sequenze di output i cui elementi sono costituiti dai risultati di operazioni eseguite sui dati di origine.

  • Creare sequenze di output in un formato diverso. Ad esempio, è possibile trasformare i dati da file di testo o righe SQL in XML.

Questi sono solo alcuni esempi. Queste trasformazioni possono ovviamente essere combinate in diversi modi nella stessa query. Inoltre, la sequenza di output di una query può essere utilizzata come sequenza di input per una nuova query.

Unione di più input in un'unica sequenza di output

È possibile utilizzare una query LINQ per creare una sequenza di output contenente elementi di più sequenze di input. Nell'esempio seguente viene illustrato come combinare due strutture dei dati in memoria, ma gli stessi principi possono essere applicati per combinare dati da XML o SQL o origini dataset. Si supponga di utilizzare i due tipi di classe seguenti:

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

Nell'esempio seguente viene illustrata la query:

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
 */

Per ulteriori informazioni, vedere Clausola join (Riferimento C#) e Clausola select (Riferimento C#).

Selezione di un sottoinsieme di ogni elemento di origine

Sono disponibili due metodi principali per selezionare un sottoinsieme di ogni elemento nella sequenza di origine:

  1. Per selezionare solo un membro dell'elemento di origine, utilizzare l'operazione punto. Nell'esempio seguente si supponga che un oggetto Customer contenga diverse proprietà pubbliche inclusa una stringa denominata City. Quando questa query viene eseguita, genererà una sequenza di stringhe di output.

    var query = from cust in Customers
                select cust.City;
    
  2. Per creare elementi che contengano più proprietà dall'elemento di origine, è possibile utilizzare un inizializzatore di oggetto con un oggetto denominato o con un tipo anonimo. Nell'esempio seguente viene illustrato l'utilizzo di un tipo anonimo per incapsulare due proprietà da ogni elemento Customer:

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

Per ulteriori informazioni, vedere Inizializzatori di oggetto e di insieme (Guida per programmatori C#) e Tipi anonimi (Guida per programmatori C#).

Trasformazione di oggetti in memoria in XML

Le query LINQ consentono di trasformare facilmente i dati tra strutture dei dati in memoria, database SQL, dataset ADO.NET e flussi o documenti XML. Nell'esempio seguente gli oggetti in una struttura dei dati in memoria vengono trasformati in elementi XML.

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

Il codice genera il seguente output XML:

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

Per ulteriori informazioni, vedere Creazione di strutture ad albero XML in C# (LINQ to XML).

Esecuzione di operazioni sugli elementi di origine

È possibile che una sequenza di output non contenga tutti gli elementi o le proprietà degli elementi della sequenza di origine. L'output potrebbe invece essere costituito da una sequenza di valori calcolata utilizzando gli elementi di origine come argomenti di input. Quando viene eseguita la query semplice riportata di seguito, viene generata una sequenza di stringhe i cui valori rappresentano un calcolo basato sulla sequenza di origine di elementi di tipo double.

Nota

Le chiamate ai metodi nelle espressioni di query non sono supportate se la query viene convertita in altri domini. Ad esempio, non è possibile chiamare un metodo C# comune in LINQ to SQL poiché SQL Server non ne supporta il contesto. È tuttavia possibile eseguire il mapping delle stored procedure ai relativi metodi e chiamare quindi le stored procedure. Per ulteriori informazioni, vedere Stored procedure (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
*/

Vedere anche

Attività

Procedura: combinare dati con LINQ utilizzando join (Visual Basic)

Riferimenti

Clausola select (Riferimento C#)

Concetti

LINQ Query Expressions (C# Programming Guide)

Altre risorse

LINQ (Language-Integrated Query)

LINQ to SQL

LINQ to DataSet

LINQ to XML