Introduction aux requêtes LINQ (C#)Introduction to LINQ Queries (C#)

Une requête est une expression qui récupère des données d’une source de données.A query is an expression that retrieves data from a data source. Les requêtes sont généralement exprimées dans un langage de requête spécialisé.Queries are usually expressed in a specialized query language. Les différents langages ont été développés au fil du temps pour les différents types de sources de données, par exemple, SQL pour les bases de données relationnelles et XQuery pour 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. Les développeurs devaient donc apprendre un nouveau langage de requête pour chaque nouveau type de source de données ou format de données qu’ils devaient prendre en charge.Therefore, developers have had to learn a new query language for each type of data source or data format that they must support. LINQLINQ simplifie cette situation en proposant un même modèle pour les différents types de sources données et les différents formats de données. simplifies this situation by offering a consistent model for working with data across various kinds of data sources and formats. Dans une requête LINQLINQ, vous travaillez toujours avec des objets.In a LINQLINQ query, you are always working with objects. Vous utilisez les mêmes modèles d’encodage de base pour interroger et transformer les données en documents XML, bases de données SQL, datasets ADO.NETADO.NET, collections .NET, et tout autre format pour lequel un fournisseur LINQLINQ est disponible.You use the same basic coding patterns to query and transform data in XML documents, SQL databases, ADO.NETADO.NET Datasets, .NET collections, and any other format for which a LINQLINQ provider is available.

Les trois parties d’une opération de requêteThree Parts of a Query Operation

Toutes les opérations de requête LINQLINQ se composent de trois actions distinctes :All LINQLINQ query operations consist of three distinct actions:

  1. Obtention de la source de donnéesObtain the data source.

  2. Création de la requêteCreate the query.

  3. Exécution de la requêteExecute the query.

L’exemple suivant montre comment les trois parties d’une opération de requête sont exprimées dans le code source.The following example shows how the three parts of a query operation are expressed in source code. Cet exemple utilise un tableau d’entiers comme source de données pour des raisons pratiques. Toutefois, ces mêmes concepts s’appliquent également aux autres sources de données.The example uses an integer array as a data source for convenience; however, the same concepts apply to other data sources also. Le reste de la rubrique fait référence à cet exemple.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);
        }
    }
}

L’illustration suivante montre l’intégralité de l’opération de requête.The following illustration shows the complete query operation. Dans LINQLINQ, l’exécution de la requête est distincte de la requête elle-même. En d’autres termes, le fait de créer une variable de requête ne permet pas d’extraire de données.In LINQLINQ the execution of the query is distinct from the query itself; in other words you have not retrieved any data just by creating a query variable.

Opération de requête LINQ complèteComplete LINQ Query Operation

Source de donnéesThe Data Source

Dans l’exemple précédent, comme la source de données est un tableau, elle prend en charge implicitement l’interface générique IEnumerable<T>.In the previous example, because the data source is an array, it implicitly supports the generic IEnumerable<T> interface. Cela signifie qu’elle peut être interrogée avec LINQLINQ.This fact means it can be queried with LINQLINQ. Une requête est exécutée dans une instruction foreach, et foreach nécessite IEnumerable ou IEnumerable<T>.A query is executed in a foreach statement, and foreach requires IEnumerable or IEnumerable<T>. Les types qui prennent en charge IEnumerable<T> ou une interface dérivée, comme l’interface générique IQueryable<T>, sont appelés des types requêtables.Types that support IEnumerable<T> or a derived interface such as the generic IQueryable<T> are called queryable types.

Un type requêtable ne nécessite aucune modification ni traitement spécial pour être utilisé comme une source de données LINQLINQ.A queryable type requires no modification or special treatment to serve as a LINQLINQ data source. Si la source de données n’est pas déjà en mémoire comme un type requêtable, le fournisseur LINQLINQ doit la représenter comme telle.If the source data is not already in memory as a queryable type, the LINQLINQ provider must represent it as such. Par exemple, LINQ to XMLLINQ to XML charge un document XML dans un type XElement requêtable :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");

Avec LINQ to SQLLINQ to SQL, vous commencez par créer un mappage O/R au moment du design, manuellement ou à l’aide des Outils LINQ to SQL de 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 in Visual Studio. Vous écrivez vos requêtes pour des objets. Ensuite, au moment de l’exécution, LINQ to SQLLINQ to SQL gère la communication avec la base de données.You write your queries against the objects, and at run-time LINQ to SQLLINQ to SQL handles the communication with the database. Dans l’exemple suivant, Customers représente une table spécifique de la base de données et le type du résultat de la requête, IQueryable<T>, dérive de 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;  

Pour plus d’informations sur la création de types de sources de données spécifiques, consultez la documentation relative aux différents fournisseurs LINQLINQ.For more information about how to create specific types of data sources, see the documentation for the various LINQLINQ providers. La règle de base est cependant très simple : une source de données LINQLINQ peut être n’importe quel objet prenant en charge l’interface générique IEnumerable<T> ou une interface qui en hérite.However, the basic rule is very simple: a LINQLINQ data source is any object that supports the generic IEnumerable<T> interface, or an interface that inherits from it.

Note

Les types tels que ArrayList qui prennent en charge l’interface non générique IEnumerable peuvent également être utilisés comme source de données LINQLINQ.Types such as ArrayList that support the non-generic IEnumerable interface can also be used as a LINQLINQ data source. Pour plus d’informations, consultez Guide pratique pour interroger une liste de tableaux avec LINQ (C#).For more information, see How to: Query an ArrayList with LINQ (C#).

La requêteThe Query

La requête spécifie les informations à récupérer à partir de la ou des sources de données.The query specifies what information to retrieve from the data source or sources. Si vous le souhaitez, une requête peut également spécifier la manière dont ces informations doivent être triées, regroupées et mises en forme avant d’être retournées.Optionally, a query also specifies how that information should be sorted, grouped, and shaped before it is returned. Une requête est stockée dans une variable de requête et initialisée avec une expression de requête.A query is stored in a query variable and initialized with a query expression. Pour faciliter l’écriture de requêtes, le langage C# propose désormais une nouvelle syntaxe de requête.To make it easier to write queries, C# has introduced new query syntax.

La requête de l’exemple précédent retourne tous les nombres pairs du tableau d’entiers.The query in the previous example returns all the even numbers from the integer array. L’expression de requête contient trois clauses : from, where et select.The query expression contains three clauses: from, where and select. Si vous connaissez le langage SQL, vous aurez remarqué que l’ordre des clauses est inverse à celui du langage SQL. La clause from spécifie la source de données, la clause where applique le filtre et la clause select spécifie le type des éléments retournés.(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. Ces clauses de requête, ainsi que certaines autres, sont abordées en détail dans la section Expressions de requête LINQ.These and the other query clauses are discussed in detail in the LINQ Query Expressions section. Pour le moment, le point important à retenir est que dans LINQLINQ, la variable de requête n’effectue aucune action et ne retourne aucune donnée.For now, the important point is that in LINQLINQ, the query variable itself takes no action and returns no data. Elle stocke simplement les informations qui seront nécessaires pour produire des résultats lors de l’exécution ultérieure de la requête.It just stores the information that is required to produce the results when the query is executed at some later point. Pour plus d’informations sur la construction des requêtes en arrière-plan, consultez Vue d’ensemble des opérateurs de requête standard (C#).For more information about how queries are constructed behind the scenes, see Standard Query Operators Overview (C#).

Note

Les requêtes peuvent également être exprimées à l’aide d’une syntaxe de méthode.Queries can also be expressed by using method syntax. Pour plus d’informations, consultez Syntaxe de requête et syntaxe de méthode dans LINQ.For more information, see Query Syntax and Method Syntax in LINQ.

Exécution de la requêteQuery Execution

Exécution différéeDeferred Execution

Comme indiqué précédemment, la variable de requête stocke uniquement les commandes de requête.As stated previously, the query variable itself only stores the query commands. L’exécution de la requête est différée jusqu’à ce que vous itériez au sein de la variable de requête dans une instruction foreach.The actual execution of the query is deferred until you iterate over the query variable in a foreach statement. Ce concept est appelé exécution différée et est illustré dans l’exemple suivant :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);
}

C’est dans l’instruction foreach que les résultats de requête sont récupérés.The foreach statement is also where the query results are retrieved. Par exemple, dans la requête précédente, la variable d’itération num contient chaque valeur (une à la fois) de la séquence retournée.For example, in the previous query, the iteration variable num holds each value (one at a time) in the returned sequence.

Étant donné que la variable de requête ne contient jamais les résultats de requête, vous pouvez l’exécuter aussi souvent que vous le voulez.Because the query variable itself never holds the query results, you can execute it as often as you like. Par exemple, vous disposez peut-être d’une base de données qui est constamment mise à jour par une application distincte.For example, you may have a database that is being updated continually by a separate application. Vous pouvez créer dans cette dernière une requête dans le but d’extraire les données les plus récentes, puis l’exécuter à intervalle régulier. Vous obtiendrez à chaque fois des résultats différents.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.

Forcer l’exécution immédiateForcing Immediate Execution

Les requêtes qui exécutent des fonctions d’agrégation sur une plage d’éléments sources doivent d’abord itérer au sein de ces éléments.Queries that perform aggregation functions over a range of source elements must first iterate over those elements. Ces requêtes sont par exemple Count, Max, Average et First.Examples of such queries are Count, Max, Average, and First. Elles s’exécutent sans instruction foreach explicite, car les requêtes doivent utiliser foreach pour retourner un résultat.These execute without an explicit foreach statement because the query itself must use foreach in order to return a result. Notez également que ces types de requêtes retournent une seule valeur, et non une collection IEnumerable.Note also that these types of queries return a single value, not an IEnumerable collection. La requête suivante retourne un nombre de chiffres pairs du tableau source :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();

Pour forcer l’exécution immédiate de n’importe quelle requête et mettre en cache ses résultats, vous pouvez appeler les méthodes ToList ou 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();

Vous pouvez également forcer l’exécution en plaçant la boucle foreach immédiatement après l’expression de requête.You can also force execution by putting the foreach loop immediately after the query expression. Toutefois, en appelant ToList ou ToArray, vous mettez également en cache toutes les données dans un même objet de collection.However, by calling ToList or ToArray you also cache all the data in a single collection object.

Voir aussiSee Also

Bien démarrer avec LINQ en C#Getting Started with LINQ in C#
Procédure pas à pas : écriture de requêtes en C#Walkthrough: Writing Queries in C#
Procédure pas à pas : écriture de requêtes en C#Walkthrough: Writing Queries in C#
Expressions de requête LINQLINQ Query Expressions
foreach, inforeach, in
Mots clés de requête (LINQ)Query Keywords (LINQ)