Notes
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page nécessite une autorisation. Vous pouvez essayer de modifier des répertoires.
Une requête est une expression qui récupère les données d’une source de données. Différentes sources de données ont différents langages de requête natifs, par exemple SQL pour les bases de données relationnelles et XQuery pour XML. Les développeurs doivent apprendre un nouveau langage de requête pour chaque type de source de données ou de format de données qu’ils doivent prendre en charge. LINQ simplifie cette situation en offrant un modèle de langage C# cohérent pour les types de sources de données et de formats. Dans une requête LINQ, vous utilisez toujours des objets C#. Vous utilisez les mêmes modèles de codage de base pour interroger et transformer des données dans des documents XML, des bases de données SQL, des collections .NET et tout autre format lorsqu’un fournisseur LINQ est disponible.
Trois parties d’une opération de requête
Toutes les opérations de requête LINQ se composent de trois actions distinctes :
- Obtenez la source de données.
- Créez la requête.
- exécutez la requête.
L’exemple suivant montre comment les trois parties d’une opération de requête sont exprimées dans le code source. L’exemple utilise un tableau d’entiers comme source de données pour des raisons pratiques ; Toutefois, les mêmes concepts s’appliquent également à d’autres sources de données. Cet exemple est mentionné dans le reste de cet article.
// The Three Parts of a LINQ Query:
// 1. Data source.
int[] numbers = [ 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’opération de requête complète. Dans LINQ, l’exécution de la requête est distincte de la requête elle-même. En d’autres termes, vous ne récupérez aucune donnée en créant une variable de requête.
Source de données
La source de données de l’exemple précédent est un tableau qui prend en charge l’interface générique IEnumerable<T> . Cela signifie qu'on peut l'interroger avec LINQ. Une requête est exécutée dans une foreach
instruction et foreach
nécessite IEnumerable ou IEnumerable<T>. Les types qui prennent en charge IEnumerable<T> ou une interface dérivée, comme le générique IQueryable<T> , sont appelés types interrogeables.
Un type interrogeable ne nécessite aucune modification ni traitement spécial pour servir de source de données LINQ. Si les données sources ne sont pas déjà en mémoire en tant que type interrogeable, le fournisseur LINQ doit le représenter en tant que tel. Par exemple, LINQ to XML charge un document XML dans un type interrogeable XElement :
// Create a data source from an XML document.
// using System.Xml.Linq;
XElement contacts = XElement.Load(@"c:\myContactList.xml");
Avec EntityFramework, vous créez un mappage relationnel objet entre les classes C# et votre schéma de base de données. Vous écrivez vos requêtes sur les objets et, au moment de l’exécution, EntityFramework gère la communication avec la base de données. Dans l’exemple suivant, Customers
représente une table spécifique dans la base de données et le type du résultat de la requête, IQueryable<T>dérive de 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 spécifiques de sources de données, consultez la documentation des différents fournisseurs LINQ. Toutefois, la règle de base est simple : une source de données LINQ est n’importe quel objet qui prend en charge l’interface générique IEnumerable<T> ou une interface qui hérite de celle-ci IQueryable<T>, généralement.
Remarque
Les types tels que ArrayList ceux qui prennent en charge l’interface non générique IEnumerable peuvent également être utilisés comme source de données LINQ. Pour plus d’informations, consultez Comment interroger un ArrayList avec LINQ (C#).
Requête
La requête spécifie les informations à récupérer à partir de la source de données ou des sources. Si vous le souhaitez, une requête spécifie également la façon dont ces informations doivent être triées, regroupées et mises en forme avant d’être retournées. Une requête est stockée dans une variable de requête et initialisée avec une expression de requête. Vous utilisez la syntaxe de requête C# pour écrire des requêtes.
La requête de l’exemple précédent retourne tous les nombres pairs du tableau entier. L’expression de requête contient trois clauses : from
, where
et select
. (Si vous connaissez SQL, vous avez remarqué que l’ordre des clauses est inversé de l’ordre dans SQL.) La from
clause spécifie la source de données, la where
clause applique le filtre et la select
clause spécifie le type des éléments retournés. Toutes les clauses de requête sont décrites en détail dans cette section. Pour l’instant, le point important est que dans LINQ, la variable de requête elle-même n’effectue aucune action et ne retourne aucune donnée. Il stocke simplement les informations requises pour produire les résultats lorsque la requête est exécutée ultérieurement. Pour plus d’informations sur la façon dont les requêtes sont construites, consultez Vue d’ensemble des opérateurs de requête standard (C#)
Remarque
Les requêtes peuvent également être exprimées à l’aide de la syntaxe de méthode. Pour plus d’informations, consultez Syntaxe de requête et syntaxe de méthode dans LINQ.
Classification des opérateurs de requête standard par mode d’exécution
Les implémentations LINQ to Objects des méthodes d’opérateur de requête standard s’exécutent de deux façons principales : immédiate ou différée. Les opérateurs de requête qui utilisent l’exécution différée peuvent également être divisés en deux catégories : la diffusion en continu et la non-diffusion.
Immédiat
L’exécution immédiate signifie que la source de données est lue et que l’opération est effectuée une seule fois. Tous les opérateurs de requête standard qui retournent un résultat scalaire s’exécutent immédiatement. Voici des exemples de telles requêtes : Count
, Max
Average
, et First
. Ces méthodes s’exécutent sans instruction explicite foreach
, car la requête elle-même doit utiliser foreach
pour retourner un résultat. Ces requêtes retournent une valeur unique, et non une IEnumerable
collection. Vous pouvez forcer n’importe quelle requête à s’exécuter immédiatement à l’aide des méthodes Enumerable.ToList ou Enumerable.ToArray. L’exécution immédiate fournit une réutilisation des résultats de requête, et non de la déclaration de requête. Les résultats sont récupérés une fois, puis stockés pour une utilisation ultérieure. La requête suivante retourne un nombre de nombres pairs dans le tableau source :
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.
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 foreach
boucle immédiatement après l’expression de requête. Toutefois, en appelant ToList
ou ToArray
, vous mettez également en cache toutes les données dans un seul objet de collection.
Reporté
L’exécution différée signifie que l’opération n’est pas effectuée au point dans le code où la requête est déclarée. L’opération est effectuée uniquement lorsque la variable de requête est énumérée, par exemple à l’aide d’une foreach
instruction. Les résultats de l’exécution de la requête dépendent du contenu de la source de données lorsque la requête est exécutée plutôt que lorsque la requête est définie. Si la variable de requête est énumérée plusieurs fois, les résultats peuvent différer à chaque fois. Presque tous les opérateurs de requête standard dont le type de retour est IEnumerable<T> ou IOrderedEnumerable<TElement> s’exécutent de manière différée. L’exécution différée fournit la fonctionnalité de réutilisation des requêtes, car la requête extrait les données mises à jour à partir de la source de données chaque fois que les résultats de la requête sont itérés. Le code suivant illustre un exemple d’exécution différée :
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
L’instruction foreach
est également l’emplacement où les résultats de la requête sont récupérés. Par exemple, dans la requête précédente, la variable num
d’itération contient chaque valeur (une à la fois) dans la séquence retournée.
Étant donné que la variable de requête elle-même ne contient jamais les résultats de la requête, vous pouvez l’exécuter à plusieurs reprises pour récupérer les données mises à jour. Par exemple, une application distincte peut mettre à jour une base de données en permanence. Dans votre application, vous pouvez créer une requête qui récupère les données les plus récentes, et vous pouvez l’exécuter à intervalles pour récupérer les résultats mis à jour.
Les opérateurs de requête qui utilisent l’exécution différée peuvent également être classés comme streaming ou non.
Diffusion en continu
Les opérateurs de streaming n’ont pas besoin de lire toutes les données sources avant de générer des éléments. Au moment de l’exécution, un opérateur de diffusion en continu effectue son opération sur chaque élément source tel qu’il est lu et génère l’élément le cas échéant. Un opérateur de streaming continue de lire les éléments sources jusqu’à ce qu’un élément de résultat puisse être produit. Cela signifie que plusieurs éléments sources peuvent être lus pour produire un élément de résultat.
Non-intégration
Les opérateurs de non-streaming doivent lire toutes les données de la source avant de pouvoir produire un élément de résultat. Les opérations telles que le tri ou le regroupement appartiennent à cette catégorie. Au moment de l’exécution, les opérateurs de requête sans flux lisent toutes les données sources, les placent dans une structure de données, effectuent l’opération et produisent les éléments résultants.
Table de classification
Le tableau suivant classifie chaque méthode d’opérateur de requête standard en fonction de sa méthode d’exécution.
Remarque
Si un opérateur est marqué dans deux colonnes, deux séquences d’entrée sont impliquées dans l’opération et chaque séquence est évaluée différemment. Dans ces cas, il s’agit toujours de la première séquence de la liste de paramètres évaluée de manière différée et en continu.
LINQ to Objects
« LINQ to Objects » fait référence à l'utilisation de requêtes LINQ sur n'importe quelle IEnumerable ou IEnumerable<T> collection directement. Vous pouvez utiliser LINQ pour interroger n’importe quelle collection énumérable, telle que List<T>, Arrayou Dictionary<TKey,TValue>. La collection peut être définie par l’utilisateur ou un type retourné par une API .NET. Dans l’approche LINQ, vous écrivez du code déclaratif qui décrit ce que vous souhaitez récupérer. LINQ to Objects fournit une excellente introduction à la programmation avec LINQ.
Les requêtes LINQ offrent trois principaux avantages par rapport aux boucles traditionnelles foreach
:
- Ils sont plus concis et lisibles, en particulier lors du filtrage de plusieurs conditions.
- Ils fournissent des fonctionnalités de filtrage, de classement et de regroupement puissantes avec un minimum de code d’application.
- Elles peuvent être transférées vers d’autres sources de données avec peu ou pas de modification.
Plus l’opération que vous souhaitez effectuer sur les données est complexe, plus vous bénéficiez de l'utilisation de LINQ au lieu des techniques d’itération traditionnelles.
Stocker les résultats d’une requête en mémoire
Une requête est essentiellement un ensemble d’instructions pour récupérer et organiser des données. Les requêtes sont exécutées de manière différée, à mesure que chaque élément dans le résultat est demandé. Lorsque vous utilisez foreach
pour itérer les résultats, les éléments sont retournés comme accessibles. Pour évaluer une requête et stocker ses résultats sans exécuter de foreach
boucle, appelez simplement l’une des méthodes suivantes sur la variable de requête :
Vous devez affecter l’objet de collection retourné à une nouvelle variable lorsque vous stockez les résultats de la requête, comme illustré dans l’exemple suivant :
List<int> numbers = [ 1, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20 ];
IEnumerable<int> queryFactorsOfFour = from num in numbers
where num % 4 == 0
select num;
// Store the results in a new variable
// without executing a foreach loop.
var factorsofFourList = queryFactorsOfFour.ToList();
// Read and write from the newly created list to demonstrate that it holds data.
Console.WriteLine(factorsofFourList[2]);
factorsofFourList[2] = 0;
Console.WriteLine(factorsofFourList[2]);