Concepts de base des expressions de requêteQuery expression basics

Cet article présente les concepts fondamentaux liés aux expressions de requête en C#.This article introduces the basic concepts related to query expressions in C#.

Qu’est-ce qu’une requête et quel est son rôle ?What is a query and what does it do?

Une requête est un jeu d’instructions qui décrit quelles données doivent être récupérées à partir d’une source (ou de sources) de données fournie, et quelles forme et organisation les données retournées doivent avoir.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. Une requête est distincte des résultats qu’elle génère.A query is distinct from the results that it produces.

De manière générale, les données sources sont organisées logiquement comme une séquence d’éléments du même type.Generally, the source data is organized logically as a sequence of elements of the same kind. Par exemple, une table de base de données SQL contient une séquence de lignes.For example, a SQL database table contains a sequence of rows. Un fichier XML contient une « séquence » d’éléments XML (bien que ceux-ci soient organisés hiérarchiquement dans une arborescence).In an XML file, there is a "sequence" of XML elements (although these are organized hierarchically in a tree structure). Une collection en mémoire contient une séquence d’objets.An in-memory collection contains a sequence of objects.

Du point de vue d’une application, le type et la structure spécifiques des données sources d’origine ne sont pas importants.From an application's viewpoint, the specific type and structure of the original source data is not important. L’application voit toujours les données sources comme une collection IEnumerable<T> ou IQueryable<T>.The application always sees the source data as an IEnumerable<T> or IQueryable<T> collection. Par exemple, dans LINQ to XML, les données sources sont rendues visibles sous la forme d’un IEnumerable<XElement.For example, in LINQ to XML, the source data is made visible as an IEnumerable<XElement>.

Compte tenu de cette séquence source, une requête peut effectuer l’une des trois actions suivantes :Given this source sequence, a query may do one of three things:

  • Récupérer un sous-ensemble des éléments pour générer une nouvelle séquence sans modifier les éléments individuels.Retrieve a subset of the elements to produce a new sequence without modifying the individual elements. La requête peut alors trier ou regrouper la séquence retournée de plusieurs façons, comme indiqué dans l’exemple suivant (supposons que scores est un 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;
    
  • Récupérer une séquence d’éléments comme dans l’exemple précédent, mais les transformer en un nouveau type d’objet.Retrieve a sequence of elements as in the previous example but transform them to a new type of object. Par exemple, une requête peut récupérer uniquement les noms de certains enregistrements de clients dans une source de données.For example, a query may retrieve only the last names from certain customer records in a data source. Elle peut aussi récupérer l’enregistrement complet, puis l’utiliser pour construire un autre type d’objet en mémoire, voire des données XML, avant de générer la séquence de résultat final.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’exemple suivant affiche une projection d’un int en string.The following example shows a projection from an int to a string. Notez le nouveau type de 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}";
    
  • Récupérer une valeur singleton sur les données sources, par exemple :Retrieve a singleton value about the source data, such as:

    • Nombre d’éléments qui correspondent à une certaine condition.The number of elements that match a certain condition.

    • Élément qui a la valeur la plus grande ou la plus petite.The element that has the greatest or least value.

    • Premier élément qui correspond à une condition, ou somme de valeurs particulières dans un jeu d’éléments spécifié.The first element that matches a condition, or the sum of particular values in a specified set of elements. Par exemple, la requête suivante retourne le nombre de notes supérieures à 80 à partir du tableau d’entiers 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();
      

      Dans l’exemple précédent, notez l’utilisation de parenthèses autour de l’expression de requête avant l’appel à la méthode Count.In the previous example, note the use of parentheses around the query expression before the call to the Count method. Vous pouvez également exprimer ceci en utilisant une nouvelle variable pour stocker le résultat concret.You can also express this by using a new variable to store the concrete result. Cette technique est plus explicite, car elle conserve la variable qui stocke la requête à un emplacement distinct de la requête qui stocke un résultat.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();
      

Dans l’exemple précédent, la requête est exécutée dans l’appel à Count, car Count doit effectuer une itération sur les résultats afin de déterminer le nombre d’éléments retournés par 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.

Qu’est-ce qu’une expression de requête ?What is a query expression?

Une expression de requête est une requête exprimée dans la syntaxe de la requête.A query expression is a query expressed in query syntax. Une expression de requête est une construction de langage de premier ordre.A query expression is a first-class language construct. Elle est similaire à toute autre expression et peut être utilisée dans tous les contextes dans lesquels une expression C# est valide.It is just like any other expression and can be used in any context in which a C# expression is valid. Une expression de requête se compose d’un jeu de clauses écrit dans une syntaxe déclarative semblable à du SQL ou du XQuery.A query expression consists of a set of clauses written in a declarative syntax similar to SQL or XQuery. Chaque clause contient à son tour une ou plusieurs expressions C#, et ces expressions peuvent elles-mêmes être une expression de requête ou contenir une expression de requête.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.

Une expression de requête doit commencer par une clause from et doit se terminer par une clause select ou group.A query expression must begin with a from clause and must end with a select or group clause. Entre la première clause from et la dernière clause select ou group, elle peut contenir une ou plusieurs clauses facultatives : where, orderby, join, let et même d’autres clauses from.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. Vous pouvez également utiliser le mot clé into pour que le résultat d’une clause join ou group puisse servir de source pour des clauses de requête supplémentaires dans la même expression de requête.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.

Variable de requêteQuery variable

Dans LINQ, une variable de requête correspond à n’importe quelle variable qui stocke une requête au lieu des résultats d’une requête.In LINQ, a query variable is any variable that stores a query instead of the results of a query. Plus spécifiquement, une variable de requête est toujours un type énumérable qui produit une séquence d’éléments quand elle est itérée dans une instruction foreach ou un appel direct à sa méthode 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’exemple de code suivant montre une expression de requête simple avec une source de données, une clause de filtrage, une clause de classement et aucune transformation des éléments sources.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 clause select termine la requête.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      

Dans l’exemple précédent, scoreQuery est une variable de requête qui est parfois désignée simplement sous le nom de requête.In the previous example, scoreQuery is a query variable, which is sometimes referred to as just a query. La variable de requête ne stocke aucune donnée de résultat réelle, générée dans la boucle foreach.The query variable stores no actual result data, which is produced in the foreach loop. De plus, quand l’instruction foreach s’exécute, les résultats de la requête ne sont pas retournés via la variable de requête scoreQuery.And when the foreach statement executes, the query results are not returned through the query variable scoreQuery. Au lieu de cela, ils sont retournés via la variable d’itération testScore.Rather, they are returned through the iteration variable testScore. La variable scoreQuery peut être itérée dans une deuxième boucle foreach.The scoreQuery variable can be iterated in a second foreach loop. Elle générera les mêmes résultats tant que ni elle ni la source de données ne sont modifiées.It will produce the same results as long as neither it nor the data source has been modified.

Une variable de requête peut stocker une requête exprimée dans la syntaxe de requête ou dans la syntaxe de méthode, ou dans une combinaison des deux.A query variable may store a query that is expressed in query syntax or method syntax, or a combination of the two. Dans les exemples suivants, queryMajorCities et queryMajorCities2 sont des variables de requête :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);

En revanche, les deux exemples suivants affichent des variables qui ne sont pas des variables de requête, même si chacune d’entre elles est initialisée avec une requête.On the other hand, the following two examples show variables that are not query variables even though each is initialized with a query. Il ne s’agit pas de variables de requête, car elles stockent des résultats :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();

Pour plus d’informations sur les différents modes d’expression de requêtes, consultez Syntaxe de requête et syntaxe de méthode dans LINQ.For more information about the different ways to express queries, see Query syntax and method syntax in LINQ.

Types explicites et implicites de variables de requêteExplicit and implicit typing of query variables

Cette documentation fournit généralement le type explicite de la variable de requête pour afficher la relation de type entre la variable de requête et la clause 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. Toutefois, vous pouvez également utiliser le mot clé var pour indiquer au compilateur de déduire le type d’une variable de requête (ou toute autre variable locale) au moment de la compilation.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. Par exemple, l’exemple de requête expliqué précédemment dans cette rubrique peut également être exprimé à l’aide de types implicites :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;

Pour plus d’informations, consultez Variables locales implicitement typées et Relations des types dans des opérations de requête LINQ.For more information, see Implicitly typed local variables and Type relationships in LINQ query operations.

Démarrage d’une expression de requêteStarting a query expression

Une expression de requête doit commencer par une clause from.A query expression must begin with a from clause. Elle spécifie une source de données avec une variable de portée.It specifies a data source together with a range variable. La variable de portée représente chaque élément consécutif dans la séquence source comme la séquence source parcourue.The range variable represents each successive element in the source sequence as the source sequence is being traversed. La variable de portée est fortement typée selon le type d’éléments dans la source de données.The range variable is strongly typed based on the type of elements in the data source. Dans l’exemple suivant, comme countries est un tableau d’objets Country, la variable de portée est également de type Country.In the following example, because countries is an array of Country objects, the range variable is also typed as Country. Étant donné que la variable de portée est fortement typée, vous pouvez utiliser l’opérateur point pour accéder à tous les membres disponibles du type.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 variable de portée est dans la portée tant que la requête n’est pas quittée avec un point-virgule ou une clause continuation.The range variable is in scope until the query is exited either with a semicolon or with a continuation clause.

Une expression de requête peut contenir plusieurs clauses from.A query expression may contain multiple from clauses. Utilisez des clauses from supplémentaires quand chaque élément de la séquence source est lui-même une collection ou contient une collection.Use additional from clauses when each element in the source sequence is itself a collection or contains a collection. Par exemple, supposons que vous avez une collection d’objets Country et que chacun d’entre eux contient une collection d’objets City nommés Cities.For example, assume that you have a collection of Country objects, each of which contains a collection of City objects named Cities. Pour interroger les objets City dans chaque Country, utilisez deux clauses from comme indiqué ici :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;

Pour plus d’informations, consultez from, clause.For more information, see from clause.

Fin d’une expression de requêteEnding a query expression

Une expression de requête doit se terminer par une clause group ou une clause select.A query expression must end with either a group clause or a select clause.

group, clausegroup clause

Utilisez la clause group pour générer une séquence de groupes organisée par une clé que vous spécifiez.Use the group clause to produce a sequence of groups organized by a key that you specify. La clé peut correspondre à tout type de données.The key can be any data type. Par exemple, la requête suivante crée une séquence de groupes qui contient un ou plusieurs objets Country dont la clé est une valeur 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];

Pour plus d’informations sur le regroupement, consultez group, clause.For more information about grouping, see group clause.

select, clauseselect clause

Utilisez la clause select pour générer tous les autres types de séquences.Use the select clause to produce all other types of sequences. Une clause select simple génère simplement une séquence du même type d’objets que les objets contenus dans la source de données.A simple select clause just produces a sequence of the same type of objects as the objects that are contained in the data source. Dans cet exemple, la source de données contient des objets Country.In this example, the data source contains Country objects. La clause orderby trie simplement les éléments dans un nouvel ordre et la clause select génère une séquence des objets Country réorganisés.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 clause select peut être utilisée pour transformer des données sources en séquences de nouveaux types.The select clause can be used to transform source data into sequences of new types. Cette transformation est également appelée projection.This transformation is also named a projection. Dans l’exemple suivant, la clause select projette une séquence de types anonymes qui contient uniquement un sous-ensemble des champs dans l’élément d’origine.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. Notez que les nouveaux objets sont initialisés à l’aide d’un initialiseur d’objet.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 };

Pour plus d’informations sur toutes les façons d’utiliser une clause select pour transformer des données sources, consultez select, clause.For more information about all the ways that a select clause can be used to transform source data, see select clause.

Continuations avec « into »Continuations with "into"

Vous pouvez utiliser le mot clé into dans une clause select ou group pour créer un identificateur temporaire qui stocke une requête.You can use the into keyword in a select or group clause to create a temporary identifier that stores a query. Procédez ainsi quand vous devez effectuer des opérations de requête supplémentaires sur une requête après une opération de regroupement ou de sélection.Do this when you must perform additional query operations on a query after a grouping or select operation. Dans l’exemple suivant, les countries sont regroupés en fonction du remplissage, par plages de 10 millions.In the following example countries are grouped according to population in ranges of 10 million. Une fois ces groupes créés, des clauses supplémentaires éliminent des groupes par filtrage, puis trient les groupes par ordre croissant.After these groups are created, additional clauses filter out some groups, and then to sort the groups in ascending order. Pour effectuer ces opérations supplémentaires, la continuation représentée par countryGroup est requise.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);
}

Pour plus d’informations, consultez into.For more information, see into.

Filtrage, classement et jointureFiltering, ordering, and joining

Entre la clause from initiale et la clause select ou group finale, toutes les autres clauses (where, join, orderby, from, let) sont facultatives.Between the starting from clause, and the ending select or group clause, all other clauses (where, join, orderby, from, let) are optional. Chacune des clauses facultatives peut être utilisée zéro fois ou plusieurs fois dans un corps de requête.Any of the optional clauses may be used zero times or multiple times in a query body.

where, clausewhere clause

Utilisez la clause where pour éliminer par filtrage des éléments des données sources selon une ou plusieurs expressions de prédicat.Use the where clause to filter out elements from the source data based on one or more predicate expressions. La clause where de l’exemple suivant a un prédicat avec deux conditions.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;

Pour plus d’informations, consultez where, clause.For more information, see where clause.

orderby, clauseorderby clause

Utilisez la clause orderby pour trier les résultats par ordre croissant ou décroissant.Use the orderby clause to sort the results in either ascending or descending order. Vous pouvez également spécifier des ordres de tri secondaires.You can also specify secondary sort orders. L’exemple suivant effectue un tri principal sur les objets country en utilisant la propriété Area.The following example performs a primary sort on the country objects by using the Area property. Il effectue ensuite un tri secondaire en utilisant la propriété 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;

Le mot clé ascending est facultatif ; il s’agit de l’ordre de tri par défaut si aucun ordre n’est spécifié.The ascending keyword is optional; it is the default sort order if no order is specified. Pour plus d’informations, consultez orderby, clause.For more information, see orderby clause.

join, clausejoin clause

Utilisez la clause join pour associer et/ou combiner des éléments d’une source de données avec des éléments d’une autre source de données en fonction d’une comparaison d’égalité entre des clés spécifiées dans chaque élément.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. Dans LINQ, les opérations de jointure sont effectuées sur les séquences des objets dont les éléments sont des types différents.In LINQ, join operations are performed on sequences of objects whose elements are different types. Après avoir joint deux séquences, vous devez utiliser une instruction select ou group pour spécifier quel élément stocker dans la séquence de sortie.After you have joined two sequences, you must use a select or group statement to specify which element to store in the output sequence. Vous pouvez également utiliser un type anonyme pour combiner des propriétés de chaque jeu d’éléments associés dans un nouveau type pour la séquence de sortie.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’exemple suivant associe des objets prod dont la propriété Category correspond à l’une des catégories dans le tableau de chaînes categories.The following example associates prod objects whose Category property matches one of the categories in the categories string array. Les produits dont la propriété Category ne correspond pas à une chaîne quelconque dans categories sont éliminés par filtrage. L’instruction select projette un nouveau type dont les propriétés sont extraites de cat et de prod.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 };

Vous pouvez également effectuer une jointure groupée en stockant les résultats de l’opération join dans une variable temporaire à l’aide du mot clé 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. Pour plus d’informations, consultez join, clause.For more information, see join clause.

let, clauselet clause

Utilisez la clause let pour stocker le résultat d’une expression telle qu’un appel de méthode dans une nouvelle variable de portée.Use the let clause to store the result of an expression, such as a method call, in a new range variable. Dans l’exemple suivant, la variable de portée firstName stocke le premier élément du tableau de chaînes retourné par 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

Pour plus d’informations, consultez let, clause.For more information, see let clause.

Sous-requêtes dans une expression de requêteSubqueries in a query expression

Une clause de requête peut elle-même contenir une expression de requête, qui est parfois connue sous le nom de sous-requête.A query clause may itself contain a query expression, which is sometimes referred to as a subquery. Chaque sous-requête démarre avec sa propre clause from qui ne pointe pas nécessairement vers la même source de données dans la première clause from.Each subquery starts with its own from clause that does not necessarily point to the same data source in the first from clause. Par exemple, la requête suivante montre une expression de requête utilisée dans l’instruction select pour récupérer les résultats d’une opération de regroupement.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()
    };

Pour plus d’informations, consultez Guide pratique pour effectuer une sous-requête sur une opération de regroupement.For more information, see How to: perform a subquery on a grouping operation.

Voir aussiSee also