Une requête est une expression qui récupère des données d'une source de données. En général, les requêtes sont exprimées dans un langage de requête spécialisé. Au fil du temps, différents langages ont été développés pour les divers types de sources de données, par exemple, SQL pour les bases de données relationnelles et XQuery pour le XML.Par conséquent, les développeurs ont dû apprendre un nouveau langage de requête pour chaque type de source de données ou format de données qu'ils doivent prendre en charge. LINQ simplifie cette situation en proposant un modèle cohérent qui permet d'utiliser des données de types de sources et de formats divers. Dans une requête LINQ, vous travaillez toujours avec des objets. Vous utilisez les mêmes modèles de codage de base pour interroger et transformer des données en documents XML, en bases de données SQL, en groupes de données ADO.NET, en collections .NET et en tout autre format pour lesquels un fournisseur LINQ est disponible.
Toutes les opérations de requête LINQ comportent trois actions distinctes :
Obtenir la source de données.
Créer la requête.
Exécuter 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. Il utilise un tableau d'entiers comme source de données pour des raisons pratiques, mais les mêmes concepts sont également applicables à d'autres sources de données. Cet exemple sert de référence dans le reste de cette rubrique.
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
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 présente la totalité de l'opération de requête. Dans LINQ; l'exécution de la requête est distincte de la requête elle-même. En d'autres termes, vous n'avez pas récupéré de données en créant simplement une variable de requête.
Dans l'exemple précédent, étant donné que la source de données est un tableau, elle prend en charge implicitement l'interface IEnumerable<T> générique. Cela signifie qu'elle peut être interrogée avec LINQ. Une requête est exécutée dans une instruction foreach et foreach requiert IEnumerable ou IEnumerable<T>. Les types qui prennent en chargeIEnumerable<T> ou une interface dérivée, telle que le IQueryable<T> générique, sont des types pouvant faire l'objet d'une requête.
Un type requêtable 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 comme type requêtable, le fournisseur LINQ doit les représenter comme telles. Par exemple, LINQ to XML charge un document XML dans un type XElement requêtable :
// Create a data source from an XML document.
// using System.Xml.Linq;
XElement contacts = XElement.Load(@"c:\myContactList.xml");
Avec LINQ to SQL, vous créez tout d'abord un mappage objet/relationnel au moment du design, soit manuellement, soit à l'aide du Concepteur Objet/Relationnel (Concepteur O/R). Vous écrivez vos requêtes sur les objets et LINQ to SQL gère la communication avec la base de données au moment de l'exécution. Dans l'exemple suivant, Customersrepré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 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 des différents fournisseurs LINQ. Toutefois, la règle de base est très simple : une source de données LINQ correspond à tout type d'objet qui prend en charge l'interface IEnumerable<T> générique ou une interface qui hérite de celle-ci.
Remarque |
|
La requête spécifie les informations à récupérer de la source ou des sources de données. Elle 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. Une requête est stockée dans une variable de requête et initialisée avec une expression de requête. C# a introduit une nouvelle syntaxe de requête pour simplifier l'écriture des requêtes.
La requête de l'exemple précédent retourne tous les nombres pairs du tableau d'entiers. L'expression de requête contient trois clauses : from, where et select. (Si vous êtes familiarisé avec SQL, vous aurez remarqué que l'ordre des clauses est inversé par rapport à l'ordre dans SQL.) La clause from spécifie la source de données, la clause whereapplique le filtre et la clause select spécifie le type des éléments retournés. Ces clauses et d'autres clauses de requête sont abordées en détail dans la section Expressions de requête LINQ (Guide de programmation C#). Pour le moment, le point majeur est que dans LINQ, la variable de requête elle-même n'exécute aucune action et ne retourne pas de données. Elle stocke simplement les informations requises pour produire les résultats lors de l'exécution ultérieure de la requête. 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.
Remarque |
|
Exécution différée
Comme indiqué précédemment, la variable de requête elle-même stocke simplement les commandes de requête. L'exécution réelle de la requête est différée jusqu'à ce que vous itériez la variable de requête dans une instruction foreach. Ce concept, connu sous le nom d'exécution différée, est illustré dans l'exemple suivant :
// Query execution.
foreach (int num in numQuery)
{
Console.Write("{0,1} ", num);
}
L'instruction foreach constitue é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 d'itération numcontient chaque valeur (une par une) de 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 aussi souvent que vous le souhaitez. Par exemple, vous pouvez mettre à jour une base de données continuellement à l'aide d'une application séparée. Dans votre application, vous pouvez créer une requête qui récupère les données les plus récentes et l'exécuter à plusieurs reprises à un intervalle donné pour récupérer des résultats différents à chaque fois.
Forcer l'exécution immédiate
Les requêtes qui exécutent des fonctions d'agrégation sur une plage d'éléments sources doivent d'abord itérer sur ces éléments. Les requêtes Count, Max, Average et First en sont quelques exemples. Elles s'exécutent sans instruction foreach explicite car la requête elle-même doit utiliser foreach pour retourner un résultat. Notez également que ces types de requêtes retournent une valeur unique et non une collection IEnumerable. La requête suivante retourne un décompte des nombres pairs dans le tableau source :
var evenNumQuery =
from num in numbers
where (num % 2) == 0
select num;
int evenNumCount = evenNumQuery.Count();
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. Toutefois, en appelant ToList ou ToArray, vous mettez également en cache toutes les données d'un objet de collection unique.
Tâches
Référence
Concepts
Autres ressources
Aucun commentaire:
Enregistrer un commentaire