Requête intégrée au langage - Language Integrated Query

Requête intégrée au langage
Conçu par Microsoft Corporation
Développeur Microsoft Corporation
Discipline de frappe Fortement typé
Site Internet docs .microsoft .com /en-us /dotnet /standard /using-linq
Les principales mises en œuvre
Langages .NET ( C# , F# , VB.NET )
Influencé par
SQL , Haskell

Language Integrated Query ( LINQ , prononcé « lien ») est un composant Microsoft .NET Framework qui ajoute des capacités d' interrogation de données natives aux langages .NET , initialement publié comme une partie importante de .NET Framework 3.5 en 2007.

LINQ étend le langage en ajoutant des expressions de requête , qui s'apparentent à des instructions SQL , et peuvent être utilisées pour extraire et traiter facilement des données à partir de tableaux , de classes énumérables , de documents XML , de bases de données relationnelles et de sources de données tierces. D'autres utilisations, qui utilisent des expressions de requête comme cadre général pour composer de manière lisible des calculs arbitraires, incluent la construction de gestionnaires d'événements ou d' analyseurs monadiques . Il définit également un ensemble de noms de méthodes (appelés opérateurs de requête standard , ou opérateurs de séquence standard ), ainsi que les règles de traduction utilisées par le compilateur pour traduire les expressions de syntaxe de requête en expressions utilisant le style fluide (appelé syntaxe de méthode par Microsoft) avec ces noms de méthode , expressions lambda et types anonymes . De nombreux concepts introduits par LINQ ont été testés à l'origine dans le projet de recherche C Microsoft de Microsoft .

Des ports de LINQ existent pour PHP ( PHPLinq ), JavaScript ( linq.js ), TypeScript ( linq.ts ) et ActionScript ( ActionLinq ), bien qu'aucun ne soit strictement équivalent à LINQ dans les langages inspirés de .NET C#, F# et VB.NET (où il fait partie du langage, pas une bibliothèque externe, et où il répond souvent à un plus large éventail de besoins).

Architecture de LINQ dans le .NET Framework

API d'opérateur de requête standard

Dans ce qui suit, les descriptions des opérateurs sont basées sur l'application du travail avec les collections. De nombreux opérateurs prennent d'autres fonctions comme arguments. Ces fonctions peuvent être fournies sous la forme d'une méthode nommée ou d'une fonction anonyme.

L'ensemble des requêtes des opérateurs définis par LINQ est exposé à l'utilisateur comme l'opérateur Query standard (SQO) API . Les opérateurs de requête pris en charge par l'API sont :

Sélectionner

L'opérateur Select effectue une projection sur la collection pour sélectionner des aspects intéressants des éléments. L'utilisateur fournit une fonction arbitraire, sous la forme d'une expression nommée ou lambda , qui projette les données membres. La fonction est transmise à l'opérateur en tant que délégué .

L'opérateur Where permet la définition d'un ensemble de règles de prédicat qui sont évaluées pour chaque objet de la collection, tandis que les objets qui ne correspondent pas à la règle sont filtrés. Le prédicat est fourni à l'opérateur en tant que délégué.

SélectionnezPlusieurs

Pour un mappage fourni par l'utilisateur des éléments de la collection aux collections, sémantiquement deux étapes sont effectuées. Tout d'abord, chaque élément est mappé à sa collection correspondante. Deuxièmement, le résultat de la première étape est aplati d'un niveau. Remarque : Select et Where sont tous deux implémentables en termes de SelectMany, tant que des collections singleton et vides sont disponibles. Les règles de traduction mentionnées ci-dessus obligent toujours un fournisseur LINQ à fournir les deux autres opérateurs.

Somme / Min / Max / Moyenne

Ces opérateurs prennent éventuellement une fonction qui récupère une certaine valeur numérique de chaque élément de la collection et l'utilise pour trouver la somme, les valeurs minimales, maximales ou moyennes de tous les éléments de la collection, respectivement. Les versions surchargées ne prennent aucune fonction et agissent comme si l'identité était donnée en tant que lambda.

Agrégat

Une somme/min/max généralisée. Cet opérateur prend une fonction qui spécifie comment deux valeurs sont combinées pour former un résultat intermédiaire ou final. En option, une valeur de départ peut être fournie, permettant au type de résultat de l'agrégation d'être arbitraire. En outre, une fonction de finalisation, prenant le résultat d'agrégation à une autre valeur, peut être fournie.

Rejoindre / Rejoindre un groupe
L'opérateur Join effectue une jointure interne sur deux collections, en fonction des clés correspondantes pour les objets de chaque collection. Il prend deux fonctions en tant que délégués, une pour chaque collection, qu'il exécute sur chaque objet de la collection pour extraire la clé de l'objet. Il faut également un autre délégué dans lequel l'utilisateur spécifie quels éléments de données, à partir des deux éléments appariés, doivent être utilisés pour créer l'objet résultant. L'opérateur GroupJoin effectue une jointure de groupe . Comme l'opérateur Select, les résultats d'une jointure sont des instanciations d'une classe différente, avec toutes les données membres des deux types d'objets source, ou un sous-ensemble d'entre eux.
Take / TakeWhile
L'opérateur Take sélectionne les n premiers objets d'une collection, tandis que l'opérateur TakeWhile, qui prend un prédicat, sélectionne les objets qui correspondent au prédicat (en s'arrêtant au premier objet qui ne lui correspond pas).
Ignorer / IgnorerPendant
Les opérateurs Skip et SkipWhile sont des compléments de Take et TakeWhile - ils ignorent les n premiers objets d'une collection, ou les objets qui correspondent à un prédicat (pour le cas de SkipWhile).
DeType
L'opérateur OfType est utilisé pour sélectionner les éléments d'un certain type.
Concat
L'opérateur Concat concatène deux collections.
Trier par / puis par
L'opérateur OrderBy est utilisé pour spécifier l'ordre de tri principal des éléments d'une collection en fonction d'une clé. L'ordre par défaut est dans l'ordre croissant, pour inverser l'ordre, l' opérateur OrderByDescending doit être utilisé. ThenBy et ThenByDescending spécifient l'ordre ultérieur des éléments. La fonction permettant d'extraire la valeur de la clé de l'objet est spécifiée par l'utilisateur en tant que délégué.
Sens inverse
L'opérateur Reverse inverse une collection.
Par groupe
L'opérateur GroupBy prend une fonction qui extrait une valeur de clé et renvoie une collection d' IGrouping<Key, Values>objets, pour chaque valeur de clé distincte. Les IGroupingobjets peuvent ensuite être utilisés pour énumérer tous les objets pour une valeur de clé particulière.
Distinct
L'opérateur Distinct supprime les instances en double d'un objet d'une collection. Une surcharge de l'opérateur prend un objet comparateur d'égalité qui définit les critères de distinction.
Union / Intersection / Sauf
Ces opérateurs sont utilisés pour effectuer une opération d' union , d' intersection et de différence sur deux séquences, respectivement. Chacun a une surcharge qui prend un objet comparateur d'égalité qui définit les critères d'égalité des éléments.
SéquenceÉgal
L'opérateur SequenceEqual détermine si tous les éléments de deux collections sont égaux et dans le même ordre.
Premier / FirstOrDefault / Last / LastOrDefault
Ces opérateurs prennent un prédicat. L'opérateur First renvoie le premier élément pour lequel le prédicat renvoie true ou, si rien ne correspond, lève une exception. L'opérateur FirstOrDefault est similaire à l'opérateur First, sauf qu'il renvoie la valeur par défaut du type d'élément (généralement une référence nulle) au cas où rien ne correspond au prédicat. Le dernier opérateur récupère le dernier élément correspondant au prédicat ou lève une exception au cas où rien ne correspondrait. LastOrDefault renvoie la valeur de l'élément par défaut si rien ne correspond.
Seul
L'opérateur Single prend un prédicat et renvoie l'élément qui correspond au prédicat. Une exception est levée si aucun ou plusieurs éléments ne correspondent au prédicat.
UniqueOuParDéfaut
L'opérateur SingleOrDefault prend un prédicat et renvoie l'élément qui correspond au prédicat. Si plusieurs éléments correspondent au prédicat, une exception est levée. Si aucun élément ne correspond au prédicat, une valeur par défaut est renvoyée.
ÉlémentAt
L'opérateur ElementAt récupère l'élément à un index donné dans la collection.
Tout / Tout
L'opérateur Any vérifie s'il y a des éléments dans la collection correspondant au prédicat. Il ne sélectionne pas l'élément, mais renvoie true si au moins un élément correspond. L'invocation de any sans prédicat renvoie true si la collection n'est pas vide. L'opérateur All renvoie true si tous les éléments correspondent au prédicat.
Contient
L'opérateur Contains vérifie si la collection contient un élément donné.
Compter
L'opérateur Count compte le nombre d'éléments dans la collection donnée. Une surcharge prenant un prédicat, compte le nombre d'éléments correspondant au prédicat.

L'API Standard Query Operator spécifie également certains opérateurs qui convertissent une collection en un autre type :

  • AsEnumerable : tape statiquement la collection sous la forme d'un fichier IEnumerable<T>.
  • AsQueryable : tape statiquement la collection sous la forme d'un fichier IQueryable<T>.
  • ToArray : crée un tableau à T[]partir de la collection.
  • ToList : crée un à List<T>partir de la collection.
  • ToDictionary : crée un à Dictionary<K, T>partir de la collection, indexé par la clé K. Une fonction de projection fournie par l'utilisateur extrait une clé de chaque élément.
  • ToLookup : crée un à Lookup<K, T>partir de la collection, indexé par la clé K. Une fonction de projection fournie par l'utilisateur extrait une clé de chaque élément.
  • Cast : convertit une collection non générique IEnumerableen une des IEnumerable<T>en transtypant chaque élément en type T. Convertit alternativement un générique IEnumerable<T>en un autre générique IEnumerable<R>en transtypant chaque élément de type Ten type R. Lève une exception dans n'importe quel élément ne peut pas être transtypé vers le type indiqué.
  • OfType : convertit une collection non générique IEnumerableen l'une des IEnumerable<T>. Convertit alternativement un générique IEnumerable<T>en un autre générique IEnumerable<R>en essayant de convertir chaque élément de type Ten type R. Dans les deux cas, seul le sous-ensemble d'éléments transtypés avec succès vers le type cible est inclus. Aucune exception n'est levée.

Extensions de langue

Bien que LINQ soit principalement implémenté en tant que bibliothèque pour .NET Framework 3.5, il définit également des extensions de langage facultatives qui font des requêtes une construction de langage de première classe et fournissent du sucre syntaxique pour l'écriture de requêtes. Ces extensions de langage ont été initialement implémentées en C# 3.0, VB 9.0 , F# et Oxygene , d'autres langages comme Nemerle ayant annoncé un support préliminaire. Les extensions de langue incluent :

  • Syntaxe de requête : Un langage est libre de choisir une syntaxe de requête qu'il reconnaîtra nativement. Ces mots-clés de langage doivent être traduits par le compilateur en appels de méthode LINQ appropriés.
  • Variables implicitement typées : cette amélioration permet de déclarer des variables sans spécifier leurs types. Les langages C# 3.0 et Oxygene les déclarent avec le varmot - clé. Dans VB9.0, le Dimmot - clé sans déclaration de type accomplit la même chose. De tels objets sont encore fortement typés ; pour ces objets, le compilateur infère les types de variables via l' inférence de type , qui permet de spécifier et de définir les résultats des requêtes sans déclarer le type des variables intermédiaires.
  • Types anonymes : les types anonymes permettent aux classes qui ne contiennent que des déclarations de membres de données d'être déduites par le compilateur. Ceci est utile pour les opérateurs Select et Join, dont les types de résultats peuvent différer des types des objets d'origine. Le compilateur utilise l'inférence de type pour déterminer les champs contenus dans les classes et génère des accesseurs et des mutateurs pour ces champs.
  • Initialiseur d'objet : les initialiseurs d'objet permettent à un objet d'être créé et initialisé dans une seule portée, comme requis pour les opérateurs Select et Join.
  • Expressions lambda : les expressions lambda permettent d'écrire des prédicats et d'autres fonctions de projection en ligne avec une syntaxe concise et prennent en charge la fermeture lexicale complète. Ils sont capturés dans des paramètres en tant que délégués ou arborescences d'expression selon le fournisseur de requêtes.

Par exemple, dans la requête pour sélectionner tous les objets d'une collection avec SomePropertymoins de 10,

var results =  from c in SomeCollection
               where c.SomeProperty < 10
               select new {c.SomeProperty, c.OtherProperty};

foreach (var result in results)
{
        Console.WriteLine(result);
}

les types de variables result , c et results sont tous déduits par le compilateur conformément aux signatures des méthodes éventuellement utilisées. La base du choix des méthodes est constituée par le résultat de la traduction sans expression de la requête

var results =
     SomeCollection
        .Where(c => c.SomeProperty < 10)
        .Select(c => new {c.SomeProperty, c.OtherProperty});

results.ForEach(x => {Console.WriteLine(x.ToString());})

Fournisseurs LINQ

La spécification C#3.0 définit un modèle d'expression de requête ainsi que des règles de traduction d'une expression LINQ vers une expression dans un sous-ensemble de C# 3.0 sans expressions LINQ. La traduction ainsi définie est en fait non typée, ce qui, en plus des expressions lambda pouvant être interprétées soit comme des délégués, soit comme des arborescences d'expressions, permet une grande flexibilité pour les bibliothèques souhaitant exposer des parties de leur interface en tant que clauses d'expression LINQ. Par exemple, LINQ to Objects fonctionne sur IEnumerable<T>s et avec des délégués, alors que LINQ to SQL utilise les arborescences d'expressions.

Les arbres d'expression sont au cœur du mécanisme d'extensibilité LINQ, grâce auquel LINQ peut être adapté à de nombreuses sources de données. Les arborescences d'expressions sont transmises aux fournisseurs LINQ, qui sont des implémentations spécifiques à la source de données qui adaptent les requêtes LINQ à utiliser avec la source de données. S'ils le souhaitent, les fournisseurs LINQ analysent les arbres d'expression contenus dans une requête afin de générer les éléments essentiels nécessaires à l'exécution d'une requête. Il peut s'agir de fragments SQL ou de toute autre représentation complètement différente du code en tant que données manipulables supplémentaires. LINQ est fourni avec des fournisseurs LINQ pour les collections d'objets en mémoire, les bases de données Microsoft SQL Server , les ensembles de données ADO.NET et les documents XML. Ces différents fournisseurs définissent les différentes saveurs de LINQ :

LINQ aux objets

Le fournisseur LINQ to Objects est utilisé pour les collections en mémoire, à l'aide du moteur d'exécution de requête local de LINQ. Le code généré par ce fournisseur fait référence à l'implémentation des opérateurs de requête standard tels que définis sur le Sequencemodèle et permet IEnumerable<T>d'interroger les collections localement. L'implémentation actuelle de LINQ to Objects effectue des vérifications d'implémentation d'interface pour permettre des tests d'appartenance, des décomptes et des opérations de recherche indexées rapides lorsqu'elles sont prises en charge par le type d'exécution de IEnumerable.

LINQ to XML (anciennement appelé XLINQ)

Le fournisseur LINQ to XML convertit un document XML en une collection d' XElementobjets, qui sont ensuite interrogés à l'aide du moteur d'exécution local fourni dans le cadre de l'implémentation de l'opérateur de requête standard.

LINQ to SQL (anciennement appelé DLINQ)

Le fournisseur LINQ to SQL permet à LINQ d'être utilisé pour interroger les bases de données Microsoft SQL Server , y compris les bases de données SQL Server Compact . Étant donné que les données SQL Server peuvent résider sur un serveur distant et que SQL Server possède son propre moteur de requête, LINQ to SQL n'utilise pas le moteur de requête de LINQ. Au lieu de cela, il convertit une requête LINQ en une requête SQL qui est ensuite envoyée à SQL Server pour traitement. Cependant, étant donné que SQL Server stocke les données en tant que données relationnelles et que LINQ fonctionne avec des données encapsulées dans des objets, les deux représentations doivent être mappées l' une à l'autre. Pour cette raison, LINQ to SQL définit également un cadre de mappage. Le mappage est effectué en définissant des classes qui correspondent aux tables de la base de données et contenant tout ou un sous-ensemble des colonnes de la table en tant que membres de données. La correspondance, ainsi que d'autres attributs de modèle relationnel tels que les clés primaires , sont spécifiés à l'aide d' attributs définis par LINQ to SQL . Par example,

[Table(Name="Customers")]
public class Customer
{
     [Column(IsPrimaryKey = true)]
     public int CustID;

     [Column]
     public string CustName;
}

Cette définition de classe correspond à une table nommée Customerset les deux données membres correspondent à deux colonnes. Les classes doivent être définies avant que LINQ to SQL puisse être utilisé. Visual Studio 2008 inclut un concepteur de mappage qui peut être utilisé pour créer le mappage entre les schémas de données dans l'objet ainsi que le domaine relationnel. Il peut créer automatiquement les classes correspondantes à partir d'un schéma de base de données , ainsi que permettre l'édition manuelle pour créer une vue différente en utilisant uniquement un sous-ensemble des tables ou des colonnes d'une table.

Le mappage est implémenté par le DataContextqui prend une chaîne de connexion au serveur et peut être utilisé pour générer un Table<T>où T est le type auquel la table de base de données sera mappée. Le Table<T>encapsule les données dans la table et implémente l' IQueryable<T>interface, de sorte que l'arborescence d'expressions est créée, que le fournisseur LINQ to SQL gère. Il convertit la requête en T-SQL et récupère le jeu de résultats du serveur de base de données. Étant donné que le traitement a lieu sur le serveur de base de données, les méthodes locales, qui ne sont pas définies comme faisant partie des expressions lambda représentant les prédicats, ne peuvent pas être utilisées. Cependant, il peut utiliser les procédures stockées sur le serveur. Toutes les modifications apportées à l'ensemble de résultats sont suivies et peuvent être renvoyées au serveur de base de données.

LINQ aux ensembles de données

Étant donné que le fournisseur LINQ to SQL (ci-dessus) fonctionne uniquement avec les bases de données Microsoft SQL Server , afin de prendre en charge toute base de données générique, LINQ inclut également LINQ to DataSets. Il utilise ADO.NET pour gérer la communication avec la base de données. Une fois que les données se trouvent dans les ensembles de données ADO.NET, LINQ to DataSets exécute des requêtes sur ces ensembles de données.

Performance

Les utilisateurs non professionnels peuvent avoir du mal avec les subtilités des fonctionnalités et de la syntaxe de LINQ to Objects . Les modèles d'implémentation naïfs de LINQ peuvent entraîner une dégradation catastrophique des performances.

Les performances de LINQ to XML et LINQ to SQL par rapport à ADO.NET dépendent du cas d'utilisation.

PLINQ

La version 4 du framework .NET inclut PLINQ , ou Parallel LINQ , un moteur d'exécution parallèle pour les requêtes LINQ. Il définit la ParallelQuery<T>classe. Toute implémentation de l' IEnumerable<T>interface peut tirer parti du moteur PLINQ en appelant la AsParallel<T>(this IEnumerable<T>)méthode d'extension définie par la classe ParallelEnumerable dans l'espace de noms System.Linq du framework .NET. Le moteur PLINQ peut exécuter des parties d'une requête simultanément sur plusieurs threads, fournissant des résultats plus rapides.

Voir également

Les références

Liens externes