Introduzione alle query LINQ (C#)Introduction to LINQ Queries (C#)

Una query è un'espressione che recupera dati da un'origine dati.A query is an expression that retrieves data from a data source. Le query sono in genere espresse in un linguaggio di query specializzato.Queries are usually expressed in a specialized query language. Nel tempo sono stati sviluppati diversi linguaggi per i vari tipi di origini dati, ad esempio SQL per database relazionali e XQuery per 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. Gli sviluppatori hanno dovuto pertanto imparare un nuovo linguaggio di query per ogni tipo di origine dati o formato dati supportato.Therefore, developers have had to learn a new query language for each type of data source or data format that they must support. LINQ semplifica questa situazione offrendo un modello coerente per l'utilizzo dei dati in diversi tipi di origini dati e formati.LINQ simplifies this situation by offering a consistent model for working with data across various kinds of data sources and formats. In una query LINQ si utilizzano sempre oggetti.In a LINQ query, you are always working with objects. Si utilizzano gli stessi modelli di codifica di base per eseguire query e trasformare i dati in documenti XML, database SQL, set di dati ADO.NET, raccolte .NET e qualsiasi altro formato per il quale è disponibile un provider LINQ.You use the same basic coding patterns to query and transform data in XML documents, SQL databases, ADO.NET Datasets, .NET collections, and any other format for which a LINQ provider is available.

Tre parti di un'operazione di queryThree Parts of a Query Operation

Tutte le operazioni di query LINQ sono costituite da tre azioni distinte:All LINQ query operations consist of three distinct actions:

  1. Ottenere l'origine dati.Obtain the data source.

  2. Creare la query.Create the query.

  3. Esecuzione della query.Execute the query.

Nell'esempio seguente viene illustrato come le tre parti di un'operazione di query vengono espresse nel codice sorgente.The following example shows how the three parts of a query operation are expressed in source code. Nell'esempio viene usata una matrice di valori interi come origine dati per motivi di praticità. Gli stessi concetti si applicano però anche ad altre origini dati.The example uses an integer array as a data source for convenience; however, the same concepts apply to other data sources also. In questo argomento si fa riferimento sempre a tale esempio.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);
        }
    }
}

Nella figura seguente viene illustrata l'operazione di query completa.The following illustration shows the complete query operation. In LINQ l'esecuzione della query è diversa dalla query stessa.In LINQ, the execution of the query is distinct from the query itself. In altre parole, non è stato recuperato alcun dato semplicemente creando una variabile di query.In other words, you have not retrieved any data just by creating a query variable.

Diagramma di un'operazione di query LINQ completa.

Origine datiThe Data Source

Poiché nell'esempio precedente è stata usata una matrice come origine dati, viene supportata implicitamente l'interfaccia generica IEnumerable<T>.In the previous example, because the data source is an array, it implicitly supports the generic IEnumerable<T> interface. Questo significa che è possibile eseguire query con LINQ.This fact means it can be queried with LINQ. Viene eseguita una query in un'istruzione foreach e foreach richiede IEnumerable o IEnumerable<T>.A query is executed in a foreach statement, and foreach requires IEnumerable or IEnumerable<T>. I tipi che supportano IEnumerable<T> o un'interfaccia derivata, ad esempio l'interfaccia generica IQueryable<T> sono denominati tipi queryable.Types that support IEnumerable<T> or a derived interface such as the generic IQueryable<T> are called queryable types.

Un tipo queryable non richiede alcuna modifica o trattamento speciale per fungere da origine dati LINQ.A queryable type requires no modification or special treatment to serve as a LINQ data source. Se i dati di origine non sono già in memoria come tipi queryable, il provider LINQ deve rappresentarlo come tale.If the source data is not already in memory as a queryable type, the LINQ provider must represent it as such. Ad esempio, LINQ to XMLLINQ to XML carica un documento XML in un tipo XElement queryable:For example, LINQ to XMLLINQ 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");

Con LINQ to SQLLINQ to SQL , è necessario innanzitutto creare un mapping relazionale a oggetti in fase di progettazione manualmente o utilizzando gli strumenti di LINQ to SQL 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. È possibile scrivere le query sugli oggetti e in fase di esecuzione LINQ to SQLLINQ to SQL gestisce la comunicazione con il database.You write your queries against the objects, and at run-time LINQ to SQLLINQ to SQL handles the communication with the database. Nell'esempio seguente Customers rappresenta una tabella specifica nel database e il tipo del risultato della query, IQueryable<T>, deriva da IEnumerable<T>.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;  

Per ulteriori informazioni sulla creazione di tipi specifici di origini dati, vedere la documentazione relativa ai vari provider LINQ.For more information about how to create specific types of data sources, see the documentation for the various LINQ providers. Tuttavia, la regola di base è molto semplice: un'origine dati LINQ è un oggetto che supporta l' IEnumerable<T> interfaccia generica o un'interfaccia che eredita da essa.However, the basic rule is very simple: a LINQ data source is any object that supports the generic IEnumerable<T> interface, or an interface that inherits from it.

Nota

I tipi, ad esempio ArrayList che supportano l'interfaccia non generica IEnumerable , possono essere utilizzati anche come origine dati LINQ.Types such as ArrayList that support the non-generic IEnumerable interface can also be used as a LINQ data source. Per ulteriori informazioni, vedere come eseguire una query su un ArrayList con LINQ (C#).For more information, see How to query an ArrayList with LINQ (C#).

QueryThe Query

La query specifica le informazioni da recuperare dall'origine o dalle origini dati.The query specifies what information to retrieve from the data source or sources. Una query può anche specificare il modo in cui ordinare, raggruppare e definire le informazioni prima che vengano restituite.Optionally, a query also specifies how that information should be sorted, grouped, and shaped before it is returned. Una query viene archiviata in una variabile di query e inizializzata con un'espressione di query.A query is stored in a query variable and initialized with a query expression. Per semplificare la scrittura delle query, in C# è stata introdotta una nuova sintassi della query.To make it easier to write queries, C# has introduced new query syntax.

La query nell'esempio precedente restituisce tutti i numeri pari dalla matrice di valori interi.The query in the previous example returns all the even numbers from the integer array. L'espressione di query contiene tre clausole: from, where e select.The query expression contains three clauses: from, where and select. Se si ha familiarità con SQL, si sarà notato che l'ordine delle clausole è invertito rispetto all'ordine in SQL. La clausola from specifica l'origine dati, la where clausola applica il filtro e la select clausola specifica il tipo degli elementi restituiti.(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. Queste e altre clausole di query sono descritte in dettaglio nella sezione LINQ (Language Integrated Query) .These and the other query clauses are discussed in detail in the Language Integrated Query (LINQ) section. Per il momento, il punto importante è che in LINQ la variabile di query stessa non esegue alcuna azione e non restituisce alcun dato.For now, the important point is that in LINQ, the query variable itself takes no action and returns no data. Archivia solo le informazioni richieste per generare i risultati quando successivamente viene eseguita la query.It just stores the information that is required to produce the results when the query is executed at some later point. Per altre informazioni sul modo in cui le query vengono costruite automaticamente, vedere Cenni preliminari sugli operatori di query standard (C#).For more information about how queries are constructed behind the scenes, see Standard Query Operators Overview (C#).

Nota

Le query possono anche essere espresse usando la sintassi del metodo.Queries can also be expressed by using method syntax. Per altre informazioni, vedere Sintassi di query e sintassi di metodi in LINQ.For more information, see Query Syntax and Method Syntax in LINQ.

Esecuzione di queryQuery Execution

Esecuzione posticipataDeferred Execution

Come indicato in precedenza, la variabile di query archivia solo i comandi della query.As stated previously, the query variable itself only stores the query commands. L'esecuzione effettiva della query è rinviata finché non si esegue l'iterazione della variabile di query in un'istruzione foreach.The actual execution of the query is deferred until you iterate over the query variable in a foreach statement. Questo concetto è detto esecuzione posticipata e viene illustrato nell'esempio seguente: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);
}

Dall'istruzione foreach vengono anche recuperati i risultati della query.The foreach statement is also where the query results are retrieved. Ad esempio, nella query precedente la variabile di iterazione num contiene ogni valore (uno alla volta) della sequenza restituita.For example, in the previous query, the iteration variable num holds each value (one at a time) in the returned sequence.

Poiché la variabile di query stessa non contiene mai i risultati della query, è possibile eseguirla un numero illimitato di volte.Because the query variable itself never holds the query results, you can execute it as often as you like. Ad esempio, è possibile avere un database che viene aggiornato continuamente mediante un'applicazione separata.For example, you may have a database that is being updated continually by a separate application. Nell'applicazione è possibile creare una query che recupera i dati più recenti ed eseguirla ripetutamente a determinati intervalli per recuperare ogni volta risultati diversi.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.

Esecuzione immediataForcing Immediate Execution

Le query che eseguono funzioni di aggregazione su un intervallo di elementi di origine devono prima eseguire l'iterazione in tali elementi.Queries that perform aggregation functions over a range of source elements must first iterate over those elements. Esempi di tali query sono Count, Max, Average e First.Examples of such queries are Count, Max, Average, and First. Queste query vengono eseguite senza un'istruzione foreach esplicita poiché la query stessa deve usare foreach per poter restituire un risultato.These execute without an explicit foreach statement because the query itself must use foreach in order to return a result. Si noti anche che questi tipi di query restituiscono un solo valore, non una raccolta IEnumerable.Note also that these types of queries return a single value, not an IEnumerable collection. Nella query seguente viene restituito un conteggio dei numeri pari nella matrice di origine: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();

Per forzare l'esecuzione immediata di una query e memorizzarne nella cache i risultati, è possibile chiamare i metodi ToList o ToArray.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();

È anche possibile forzare l'esecuzione inserendo il ciclo foreach immediatamente dopo l'espressione di query.You can also force execution by putting the foreach loop immediately after the query expression. Tuttavia, chiamando ToList o ToArray vengono memorizzati nella cache anche tutti i dati di un singolo oggetto della raccolta.However, by calling ToList or ToArray you also cache all the data in a single collection object.

Vedere ancheSee also