Nozioni fondamentali sulle espressioni di queryQuery expression basics

Questo articolo presenta i concetti di base relativi alle espressioni di query nel linguaggio C#.This article introduces the basic concepts related to query expressions in C#.

Che cos'è una query e cosa fa?What is a query and what does it do?

Una query è un set di istruzioni che descrive i dati da recuperare da una determinata origine (o più origini) dati e indica quale forma e organizzazione devono avere i dati restituiti.A query is a set of instructions that describes what data to retrieve from a given data source (or sources) and what shape and organization the returned data should have. Una query è distinta dai risultati che produce.A query is distinct from the results that it produces.

In genere, i dati di origine vengono organizzati logicamente come una sequenza di elementi dello stesso tipo.Generally, the source data is organized logically as a sequence of elements of the same kind. Ad esempio, una tabella di database SQL contiene una sequenza di righe.For example, a SQL database table contains a sequence of rows. In un file XML è presente una "sequenza" di elementi XML, anche se questi sono organizzati gerarchicamente in una struttura ad albero.In an XML file, there is a "sequence" of XML elements (although these are organized hierarchically in a tree structure). Una raccolta in memoria contiene una sequenza di oggetti.An in-memory collection contains a sequence of objects.

Dal punto di vista di un'applicazione, il tipo e la struttura specifici dei dati di origine non è importante.From an application's viewpoint, the specific type and structure of the original source data is not important. L'applicazione considera sempre i dati di origine come raccolta IEnumerable<T> o IQueryable<T>.The application always sees the source data as an IEnumerable<T> or IQueryable<T> collection. In LINQ to XML, ad esempio, i dati di origine sono resi visibili come oggetto IEnumerable<XElement>.For example, in LINQ to XML, the source data is made visible as an IEnumerable<XElement>.

Data questa sequenza di origine, una query può eseguire una delle tre operazioni seguenti:Given this source sequence, a query may do one of three things:

  • Recuperare un subset di elementi per produrre una nuova sequenza senza modificare i singoli elementi.Retrieve a subset of the elements to produce a new sequence without modifying the individual elements. La query può quindi ordinare o raggruppare la sequenza restituita in vari modi, come illustrato nell'esempio seguente (si presuppone che scores sia un elemento int[]):The query may then sort or group the returned sequence in various ways, as shown in the following example (assume scores is an int[]):

    IEnumerable<int> highScoresQuery =
        from score in scores
        where score > 80
        orderby score descending
        select score;
    
  • Recuperare una sequenza di elementi come nell'esempio precedente, ma trasformandoli in un nuovo tipo di oggetto.Retrieve a sequence of elements as in the previous example but transform them to a new type of object. Ad esempio, una query può recuperare solo i cognomi da determinati record cliente in un'origine dati.For example, a query may retrieve only the last names from certain customer records in a data source. Oppure può recuperare il record completo e quindi usarlo per creare un altro tipo di oggetto in memoria o anche dati XML prima di generare la sequenza di risultati finale.Or it may retrieve the complete record and then use it to construct another in-memory object type or even XML data before generating the final result sequence. L'esempio seguente illustra una proiezione da int a string.The following example shows a projection from an int to a string. Si noti il nuovo tipo di highScoresQuery.Note the new type of highScoresQuery.

    IEnumerable<string> highScoresQuery2 =
        from score in scores
        where score > 80
        orderby score descending
        select $"The score is {score}";
    
  • Recuperare un valore singleton sui dati di origine, ad esempio:Retrieve a singleton value about the source data, such as:

    • Il numero di elementi che corrispondono a una determinata condizione.The number of elements that match a certain condition.

    • L'elemento con il valore massimo o minimo.The element that has the greatest or least value.

    • Il primo elemento che corrisponde a una condizione o la somma di particolari valori in un set specificato di elementi.The first element that matches a condition, or the sum of particular values in a specified set of elements. Ad esempio, la query seguente restituisce il numero di punteggi superiori a 80 dalla matrice di interi scores:For example, the following query returns the number of scores greater than 80 from the scores integer array:

      int highScoreCount =
          (from score in scores
           where score > 80
           select score)
           .Count();
      

      Nell'esempio precedente si noti l'uso delle parentesi attorno all'espressione di query prima della chiamata al metodo Count.In the previous example, note the use of parentheses around the query expression before the call to the Count method. Un'espressione analoga è usare una nuova variabile per archiviare il risultato concreto.You can also express this by using a new variable to store the concrete result. Questa tecnica è più leggibile perché mantiene la variabile che contiene la query separata dalla query che archivia un risultato.This technique is more readable because it keeps the variable that stores the query separate from the query that stores a result.

      IEnumerable<int> highScoresQuery3 =
          from score in scores
          where score > 80
          select score;
      
      int scoreCount = highScoresQuery3.Count();
      

Nell'esempio precedente la query viene eseguita nella chiamata a Count, poiché Count deve eseguire l'iterazione dei risultati per determinare il numero di elementi restituiti da highScoresQuery.In the previous example, the query is executed in the call to Count, because Count must iterate over the results in order to determine the number of elements returned by highScoresQuery.

Che cos'è un'espressione di query?What is a query expression?

Un'espressione di query è una query espressa nella sintassi delle query.A query expression is a query expressed in query syntax. È un costrutto di linguaggio di prima classe.A query expression is a first-class language construct. È esattamente come qualsiasi altra espressione e può essere usata in qualsiasi contesto in cui un'espressione C# è valida.It is just like any other expression and can be used in any context in which a C# expression is valid. Un'espressione di query consiste in un set di clausole scritte in una sintassi dichiarativa simile a SQL o XQuery.A query expression consists of a set of clauses written in a declarative syntax similar to SQL or XQuery. Ogni clausola contiene a sua volta una o più espressioni C# e queste espressioni possono essere espressioni di query o contenere un'espressione di query.Each clause in turn contains one or more C# expressions, and these expressions may themselves be either a query expression or contain a query expression.

Un'espressione di query deve iniziare con una clausola from e terminare con una clausola select o group.A query expression must begin with a from clause and must end with a select or group clause. Tra la prima clausola from e l'ultima clausola select o group può contenere una o più delle seguenti clausole facoltative: where, orderby, join, let e anche clausole from aggiuntive.Between the first from clause and the last select or group clause, it can contain one or more of these optional clauses: where, orderby, join, let and even additional from clauses. È anche possibile usare la parola chiave into per consentire al risultato di una clausola join o group di funzionare come origine per le clausole di query aggiuntive nella stessa espressione di query.You can also use the into keyword to enable the result of a join or group clause to serve as the source for additional query clauses in the same query expression.

Variabile di queryQuery variable

In LINQ una variabile di query è qualsiasi variabile che archivia una query anziché i risultati di una query.In LINQ, a query variable is any variable that stores a query instead of the results of a query. In particolare, una variabile di query è sempre un tipo enumerabile che genera una sequenza di elementi quando viene iterato in un'istruzione foreach o una chiamata diretta al relativo metodo IEnumerator.MoveNext.More specifically, a query variable is always an enumerable type that will produce a sequence of elements when it is iterated over in a foreach statement or a direct call to its IEnumerator.MoveNext method.

L'esempio di codice seguente illustra un'espressione di query semplice con un'origine dati, una clausola di filtro, una clausola di ordinamento e nessuna trasformazione degli elementi di origine.The following code example shows a simple query expression with one data source, one filtering clause, one ordering clause, and no transformation of the source elements. La clausola select termina la query.The select clause ends the query.

static void Main()
{
    // Data source.
    int[] scores = { 90, 71, 82, 93, 75, 82 };

    // Query Expression.
    IEnumerable<int> scoreQuery = //query variable
        from score in scores //required
        where score > 80 // optional
        orderby score descending // optional
        select score; //must end with select or group

    // Execute the query to produce the results
    foreach (int testScore in scoreQuery)
    {
        Console.WriteLine(testScore);
    }
}
// Outputs: 93 90 82 82

Nell'esempio precedente scoreQuery è una variabile di query, che a volte viene definita semplicemente query.In the previous example, scoreQuery is a query variable, which is sometimes referred to as just a query. La variabile di query non archivia dati sul risultato effettivo, che vengono generati nel ciclo foreach.The query variable stores no actual result data, which is produced in the foreach loop. E quando viene eseguita l'istruzione foreach i risultati della query non vengono restituiti attraverso la variabile di query scoreQuery.And when the foreach statement executes, the query results are not returned through the query variable scoreQuery. Vengono piuttosto restituiti attraverso la variabile di iterazione testScore.Rather, they are returned through the iteration variable testScore. La variabile scoreQuery può essere iterata in un secondo ciclo foreach.The scoreQuery variable can be iterated in a second foreach loop. Verranno generati gli stessi risultati purché non siano state modificate né la variabile né l'origine dati.It will produce the same results as long as neither it nor the data source has been modified.

Una variabile di query può archiviare una query espressa nella sintassi di query, nella sintassi di metodo o in una combinazione delle due.A query variable may store a query that is expressed in query syntax or method syntax, or a combination of the two. Negli esempi seguenti sia queryMajorCities che queryMajorCities2 sono variabili di query:In the following examples, both queryMajorCities and queryMajorCities2 are query variables:

//Query syntax
IEnumerable<City> queryMajorCities =
    from city in cities
    where city.Population > 100000
    select city;

// Method-based syntax
IEnumerable<City> queryMajorCities2 = cities.Where(c => c.Population > 100000);

I due esempi seguenti illustrano invece le variabili che non sono variabili di query anche se ognuna viene inizializzata con una query.On the other hand, the following two examples show variables that are not query variables even though each is initialized with a query. Non sono variabili di query perché archiviano i risultati:They are not query variables because they store results:

int highestScore =
    (from score in scores
     select score)
    .Max();

// or split the expression
IEnumerable<int> scoreQuery =
    from score in scores
    select score;

int highScore = scoreQuery.Max();
// the following returns the same result
int highScore = scores.Max();

List<City> largeCitiesList =
    (from country in countries
     from city in country.Cities
     where city.Population > 10000
     select city)
       .ToList();

// or split the expression
IEnumerable<City> largeCitiesQuery =
    from country in countries
    from city in country.Cities
    where city.Population > 10000
    select city;

List<City> largeCitiesList2 = largeCitiesQuery.ToList();

Per altre informazioni sui diversi modi di esprimere le query, vedere Sintassi di query e sintassi di metodi in LINQ.For more information about the different ways to express queries, see Query syntax and method syntax in LINQ.

Tipizzazione esplicita e implicita delle variabili di queryExplicit and implicit typing of query variables

In questa documentazione viene usato in genere il tipo esplicito della variabile di query allo scopo di evidenziare la relazione di tipo tra la variabile di query e la clausola select.This documentation usually provides the explicit type of the query variable in order to show the type relationship between the query variable and the select clause. Tuttavia, è possibile usare anche la parola chiave var per indicare al compilatore di dedurre il tipo di una variabile di query, o qualsiasi altra variabile locale, in fase di compilazione.However, you can also use the var keyword to instruct the compiler to infer the type of a query variable (or any other local variable) at compile time. L'esempio di query illustrato in precedenza in questo argomento può essere espresso anche usando la tipizzazione implicita:For example, the query example that was shown previously in this topic can also be expressed by using implicit typing:

// Use of var is optional here and in all queries.
// queryCities is an IEnumerable<City> just as
// when it is explicitly typed.
var queryCities =
    from city in cities
    where city.Population > 100000
    select city;

Per altre informazioni, vedere Variabili locali tipizzate in modo implicito e Relazioni tra i tipi nelle operazioni di query LINQ.For more information, see Implicitly typed local variables and Type relationships in LINQ query operations.

Avviare un'espressione di queryStarting a query expression

Un'espressione di query deve iniziare con una clausola from.A query expression must begin with a from clause. Specifica un'origine dati insieme a una variabile di intervallo.It specifies a data source together with a range variable. La variabile di intervallo rappresenta ogni elemento successivo nella sequenza di origine man mano che si attraversa la sequenza di origine.The range variable represents each successive element in the source sequence as the source sequence is being traversed. La variabile di intervallo è fortemente tipizzata in base al tipo di elementi nell'origine dati.The range variable is strongly typed based on the type of elements in the data source. Nell'esempio seguente, poiché countries è una matrice di oggetti Country, anche la variabile di intervallo è tipizzata come Country.In the following example, because countries is an array of Country objects, the range variable is also typed as Country. Poiché la variabile di intervallo è fortemente tipizzata, è possibile usare l'operatore punto per accedere ai membri disponibili del tipo.Because the range variable is strongly typed, you can use the dot operator to access any available members of the type.

IEnumerable<Country> countryAreaQuery =
    from country in countries
    where country.Area > 500000 //sq km
    select country;

La variabile di intervallo è nell'ambito finché la query viene terminata con un punto e virgola o con una clausola continuation.The range variable is in scope until the query is exited either with a semicolon or with a continuation clause.

Un'espressione di query può contenere più clausole from.A query expression may contain multiple from clauses. Usare clausole from aggiuntive quando ogni elemento nella sequenza di origine è a sua volta una raccolta o contiene una raccolta.Use additional from clauses when each element in the source sequence is itself a collection or contains a collection. Ad esempio, si supponga di avere una raccolta di oggetti Country, ognuna delle quali contiene una raccolta di oggetti City denominata Cities.For example, assume that you have a collection of Country objects, each of which contains a collection of City objects named Cities. Per eseguire query sugli oggetti City in ogni Country, usare due clausole from come illustrato di seguito:To query the City objects in each Country, use two from clauses as shown here:

IEnumerable<City> cityQuery =
    from country in countries
    from city in country.Cities
    where city.Population > 10000
    select city;

Per altre informazioni, vedere Clausola from.For more information, see from clause.

Terminare un'espressione di queryEnding a query expression

Un'espressione di query deve terminare con una clausola group o una clausola select.A query expression must end with either a group clause or a select clause.

Clausola groupgroup clause

Usare la clausola group per produrre una sequenza di gruppi organizzata in base a una chiave specificata.Use the group clause to produce a sequence of groups organized by a key that you specify. La chiave può essere qualsiasi tipo di dati.The key can be any data type. Ad esempio, la query seguente crea una sequenza di gruppi che contiene uno o più oggetti Country e la cui chiave è un valore char.For example, the following query creates a sequence of groups that contains one or more Country objects and whose key is a char value.

var queryCountryGroups =
    from country in countries
    group country by country.Name[0];

Per altre informazioni sul raggruppamento, vedere Clausola group.For more information about grouping, see group clause.

Clausola selectselect clause

Usare la clausola select per creare tutti gli altri tipi di sequenze.Use the select clause to produce all other types of sequences. Una clausola select semplice produce una sequenza usando lo stesso tipo di oggetti dell'origine dati.A simple select clause just produces a sequence of the same type of objects as the objects that are contained in the data source. In questo esempio l'origine dati contiene oggetti Country.In this example, the data source contains Country objects. La clausola orderby si limita a ordinare gli elementi in base a un nuovo ordine e la clausola select produce una sequenza degli oggetti Country riordinati.The orderby clause just sorts the elements into a new order and the select clause produces a sequence of the reordered Country objects.

IEnumerable<Country> sortedQuery =
    from country in countries
    orderby country.Area
    select country;

La clausola select può essere usata per trasformare i dati di origine in sequenze di nuovi tipi.The select clause can be used to transform source data into sequences of new types. Questa trasformazione è detta anche proiezione.This transformation is also named a projection. Nell'esempio seguente la clausola selectproietta una sequenza di tipi anonimi che contiene solo un subset dei campi dell'elemento originale.In the following example, the select clause projects a sequence of anonymous types which contains only a subset of the fields in the original element. Si noti che i nuovi oggetti vengono inizializzati usando un inizializzatore di oggetto.Note that the new objects are initialized by using an object initializer.

// Here var is required because the query
// produces an anonymous type.
var queryNameAndPop =
    from country in countries
    select new { Name = country.Name, Pop = country.Population };

Per altre informazioni su tutti i modi in cui una clausola select può essere usata per trasformare i dati di origine, vedere Clausola select.For more information about all the ways that a select clause can be used to transform source data, see select clause.

Continuazioni con "into"Continuations with "into"

È possibile usare la parola chiave into in una clausola select o group per creare un identificatore temporaneo che archivia una query.You can use the into keyword in a select or group clause to create a temporary identifier that stores a query. Eseguire questa operazione quando è necessario eseguire altre operazioni di query per una query dopo un'operazione di raggruppamento o selezione.Do this when you must perform additional query operations on a query after a grouping or select operation. Nell'esempio seguente countries indica i paesi raggruppati in base alla popolazione in intervalli di 10 milioni.In the following example countries are grouped according to population in ranges of 10 million. Dopo avere creato questi gruppi, le clausole aggiuntive escludono alcuni gruppi, quindi ordinano i gruppi in ordine crescente.After these groups are created, additional clauses filter out some groups, and then to sort the groups in ascending order. Per eseguire le operazioni aggiuntive, è richiesta la continuazione rappresentata da countryGroup.To perform those additional operations, the continuation represented by countryGroup is required.

// percentileQuery is an IEnumerable<IGrouping<int, Country>>
var percentileQuery =
    from country in countries
    let percentile = (int) country.Population / 10_000_000
    group country by percentile into countryGroup
    where countryGroup.Key >= 20
    orderby countryGroup.Key
    select countryGroup;

// grouping is an IGrouping<int, Country>
foreach (var grouping in percentileQuery)
{
    Console.WriteLine(grouping.Key);
    foreach (var country in grouping)
        Console.WriteLine(country.Name + ":" + country.Population);
}

Per altre informazioni, vedere into.For more information, see into.

Filtro, ordinamento e joinFiltering, ordering, and joining

Tra la clausola iniziale from e la clausola finale select o group, tutte le altre clausole (where, join, orderby, from, let) sono facoltative.Between the starting from clause, and the ending select or group clause, all other clauses (where, join, orderby, from, let) are optional. Qualsiasi clausola facoltativa può essere usata zero o più volte nel corpo di una query.Any of the optional clauses may be used zero times or multiple times in a query body.

Clausola wherewhere clause

Usare la clausola where per escludere gli elementi dai dati di origine in base a una o più espressioni del predicato.Use the where clause to filter out elements from the source data based on one or more predicate expressions. La clausola where nell'esempio seguente include un predicato con due condizioni.The where clause in the following example has one predicate with two conditions.

IEnumerable<City> queryCityPop =
    from city in cities
    where city.Population < 200000 && city.Population > 100000
    select city;

Per ulteriori informazioni, vedere clausola where.For more information, see where clause.

Clausola orderbyorderby clause

Usare la clausola orderby per ordinare i risultati in ordine crescente o decrescente.Use the orderby clause to sort the results in either ascending or descending order. È anche possibile specificare gli ordinamenti secondari.You can also specify secondary sort orders. Nell'esempio seguente viene eseguito un ordinamento primario per gli oggetti country usando la proprietà Area.The following example performs a primary sort on the country objects by using the Area property. Viene quindi eseguito un ordinamento secondario usando la proprietà Population.It then performs a secondary sort by using the Population property.

IEnumerable<Country> querySortedCountries =
    from country in countries
    orderby country.Area, country.Population descending
    select country;

La parola chiave ascending è facoltativa, ma consente l'ordinamento predefinito se non viene specificato alcun ordine.The ascending keyword is optional; it is the default sort order if no order is specified. Per altre informazioni, vedere Clausola orderby.For more information, see orderby clause.

Clausola joinjoin clause

Usare la clausola join per associare e/o combinare gli elementi di un'origine dati con gli elementi di un'altra origine dati in base a un confronto di uguaglianza tra le chiavi specificate in ogni elemento.Use the join clause to associate and/or combine elements from one data source with elements from another data source based on an equality comparison between specified keys in each element. In LINQ le operazioni di join vengono eseguite su sequenze di oggetti i cui elementi sono tipi diversi.In LINQ, join operations are performed on sequences of objects whose elements are different types. Dopo avere unito due sequenze, è necessario usare un'istruzione select o group per specificare l'elemento da archiviare nella sequenza di output.After you have joined two sequences, you must use a select or group statement to specify which element to store in the output sequence. È anche possibile usare un tipo anonimo per combinare le proprietà da ogni set di elementi associati in un nuovo tipo per la sequenza di output.You can also use an anonymous type to combine properties from each set of associated elements into a new type for the output sequence. L'esempio seguente associa oggetti prod la cui proprietà Category corrisponde a una delle categorie nella matrice di stringhe categories.The following example associates prod objects whose Category property matches one of the categories in the categories string array. I Category prodotti che non categories corrispondono ad alcuna stringa in vengono filtrati. L'istruzione select proietta un nuovo tipo cat le prodcui proprietà sono tratte da entrambi e .Products whose Category does not match any string in categories are filtered out. The select statement projects a new type whose properties are taken from both cat and prod.

var categoryQuery =
    from cat in categories
    join prod in products on cat equals prod.Category
    select new { Category = cat, Name = prod.Name };

È anche possibile creare un join di gruppo archiviando i risultati dell'operazione join in una variabile temporanea usando la parola chiave into.You can also perform a group join by storing the results of the join operation into a temporary variable by using the into keyword. Per ulteriori informazioni, vedere Clausola join.For more information, see join clause.

Clausola letlet clause

Usare la clausola let per archiviare il risultato di un'espressione, ad esempio una chiamata al metodo, in una nuova variabile di intervallo.Use the let clause to store the result of an expression, such as a method call, in a new range variable. Nell'esempio seguente la variabile di intervallo firstName archivia il primo elemento della matrice di stringhe restituita da Split.In the following example, the range variable firstName stores the first element of the array of strings that is returned by Split.

string[] names = { "Svetlana Omelchenko", "Claire O'Donnell", "Sven Mortensen", "Cesar Garcia" };
IEnumerable<string> queryFirstNames =
    from name in names
    let firstName = name.Split(' ')[0]
    select firstName;

foreach (string s in queryFirstNames)
    Console.Write(s + " ");
//Output: Svetlana Claire Sven Cesar

Per altre informazioni, vedere Clausola let.For more information, see let clause.

Sottoquery in un'espressione di querySubqueries in a query expression

Una clausola di query può contenere un'espressione di query, a volte detta sottoquery.A query clause may itself contain a query expression, which is sometimes referred to as a subquery. Ogni sottoquery inizia con la propria clausola from che non fa necessariamente riferimento alla stessa origine dati nella prima clausola from.Each subquery starts with its own from clause that does not necessarily point to the same data source in the first from clause. Ad esempio, la query seguente rappresenta un'espressione di query usate nell'istruzione select per recuperare i risultati di un'operazione di raggruppamento.For example, the following query shows a query expression that is used in the select statement to retrieve the results of a grouping operation.

var queryGroupMax =
    from student in students
    group student by student.GradeLevel into studentGroup
    select new
    {
        Level = studentGroup.Key,
        HighestScore =
            (from student2 in studentGroup
             select student2.Scores.Average())
             .Max()
    };

Per ulteriori informazioni, vedere Eseguire una sottoquery su un'operazione di raggruppamento.For more information, see Perform a subquery on a grouping operation.

Vedere ancheSee also