Considérations sur LINQ (WCF Data Services)
Cette rubrique fournit des informations sur la façon dont les requêtes LINQ sont composées et exécutées lorsque vous utilisez le client Services de données WCF et décrit les restrictions d'utilisation de LINQ pour interroger un service de données qui implémente Protocole OData (Open Data). Pour plus d'informations sur le sujet suivant la composition et l'exécution des requêtes sur un service de données basé sur OData, consultez Interrogation du service de données (WCF Data Services).
Cette rubrique contient les sections suivantes :
Composition de requêtes LINQ
LINQ vous permet de composer des requêtes pour interroger une collection d'objets qui implémente IEnumerable<T>. La boîte de dialogue Ajouter une référence de service dans Visual Studio et l'outil DataSvcUtil.exe sont utilisés pour générer la représentation d'un service OData sous forme de classe de conteneur d'entités qui hérite de DataServiceContext, ainsi que des objets qui représentent les entités retournées dans les flux. Ces outils génèrent également des propriétés sur la classe de conteneur d'entités des collections qui sont exposées en tant que flux par le service. Chacune de ces propriétés de classe qui encapsule le service de données retourne un DataServiceQuery<TElement>. Étant donné que la classe DataServiceQuery<TElement> implémente l'interface IQueryable<T> définie par LINQ, vous pouvez composer une requête LINQ sur des flux exposés par le service de données, qui sont convertis par la bibliothèque cliente en un URI de demande de requête envoyé au service de données lors de l'exécution.
Important
L'ensemble de requêtes pouvant être exprimées dans la syntaxe LINQ est plus étendu que dans la syntaxe d'URI utilisée par les services de données OData.NotSupportedException est levée lorsque la requête ne peut pas être mappée à un URI dans le service de données cible.Pour plus d'informations, consultez sur les Unsupported LINQ Methods dans cette rubrique.
L'exemple suivant est une requête LINQ qui retourne des Orders ayant un coût de fret supérieur à $30 et trie les résultats par date d'expédition, en commençant par la dernière :
Dim selectedOrders = From o In context.Orders _
Where (o.Freight > 30) _
Order By o.ShippedDate Descending _
Select o
var selectedOrders = from o in context.Orders
where o.Freight > 30
orderby o.ShippedDate descending
select o;
Cette requête LINQ est traduite dans l'URI de requête suivant exécuté sur le service de données démarrage rapide basé sur Northwind :
https://localhost:12345/Northwind.svc/Orders?Orderby=ShippedDate&?filter=Freight gt 30
Pour des informations générales sur LINQ, consultez Language-Integrated Query (LINQ).
LINQ vous permet de composer des requêtes en utilisant aussi bien la syntaxe déclarative spécifique au langage, illustrée dans l'exemple précédent, qu'un ensemble de méthodes de requête qu'on nomme opérateurs de requête standard. Une requête équivalente à l'exemple précédent peut être composée en utilisant uniquement la syntaxe reposant sur une méthode, comme illustré dans l'exemple suivant :
Dim selectedOrders = context.Orders _
.Where(Function(o) o.Freight.Value > 30) _
.OrderByDescending(Function(o) o.ShippedDate)
var selectedOrders = context.Orders
.Where(o => o.Freight > 30)
.OrderByDescending(o => o.ShippedDate);
Le client Services de données WCF peut traduire ces deux types de requêtes composées dans un URI de requête, et vous pouvez étendre une requête LINQ en ajoutant des méthodes de requête à une expression de requête. Lorsque vous composez des requêtes LINQ en ajoutant une syntaxe de méthode à une expression de requête ou un DataServiceQuery<TElement>, les opérations sont ajoutées à l'URI de la requête dans l'ordre suivant lequel les méthodes sont appelées. Cela équivaut à appeler la méthode AddQueryOption(String, Object) pour ajouter chaque option de requête à l'URI de requête.
Exécution de requêtes LINQ
Lorsqu'elles sont ajoutées à une requête, certaines méthodes de requête LINQ, comme First<TSource> ou Single<TSource>, provoquent son exécution. L'exécution de la requête est également déclenchée lorsque les résultats sont énumérés implicitement, comme lors d'une boucle foreach ou lorsque la requête est attribuée à une collection List. Pour plus d'informations, consultez Interrogation du service de données (WCF Data Services).
Le client exécute une requête LINQ en deux parties. Lorsque cela est possible, les expressions LINQ dans une requête sont d'abord évaluées sur le client, puis une requête basée surl' URI est générée et envoyée au service de données pour être évaluée par rapport aux données dans le service. Pour plus d'informations, consultez la section Client versus Server Execution dans Interrogation du service de données (WCF Data Services).
Lorsqu'une requête LINQ ne peut pas être traduite dans un URI de requête compatible avec OData, une exception est levée en cas de tentative d'exécution. Pour plus d'informations, consultez Interrogation du service de données (WCF Data Services).
Exemples de requêtes LINQ
Les exemples des sections qui suivent illustrent les types de requêtes LINQ pouvant être exécutés sur un service OData.
Filtrage
Les exemples de requêtes LINQ de cette section filtrent les données dans le flux retourné par le service.
Les exemples suivants illustrent des requêtes équivalentes qui filtrent les entités Orders retournées afin que seules les commandes ayant un coût de fret supérieur à $30 soient retournées :
Utilisation de la syntaxe de requête LINQ :
Dim filteredOrders = From o In context.Orders Where o.Freight.Value > 30 Select o
var filteredOrders = from o in context.Orders where o.Freight > 30 select o;
Utilisation des méthodes de requête LINQ :
Dim filteredOrders = context.Orders.Where(Function(o) o.Freight.Value > 0)
var filteredOrders = context.Orders .Where(o => o.Freight > 30);
Option $filter de la chaîne de requête d'URI :
' Define a query for orders with a Freight value greater than 30. Dim filteredOrders _ = context.Orders.AddQueryOption("$filter", "Freight gt 30M")
// Define a query for orders with a Freight value greater than 30. var filteredOrders = context.Orders.AddQueryOption("$filter", "Freight gt 30M");
Tous les exemples précédents sont convertis vers l'URI de requête : https://localhost:12345/northwind.svc/Orders()?$filter=Freight gt 30M.
Vous pouvez également utiliser les opérateurs All<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) et Any<TSource>(IEnumerable<TSource>) pour composer des requêtes permettant de filtrer les entités en fonction des propriétés des collections. Dans ce cas, le prédicat est évalué par rapport aux propriétés retournant les collections d'entités connexes et les collections de types complexes et primitifs. Par exemple, la requête suivante retourne n'importe quel employé dont la description du territoire contient la chaîne fournie :
Dim filteredEmployees = From e In context.Employees _
Where e.Territories.Any(Function(t) t.TerritoryDescription.Contains(territory))
Select e
var filteredEmployees = from e in context.Employees
where e.Territories.Any(t => t.TerritoryDescription.Contains(territory))
select e;
Dans cette requête, l'opérateur Any<TSource>(IEnumerable<TSource>) vous permet de parcourir l'association plusieurs-à-plusieurs entre Employees et Territories afin de filtrer les employés en fonction de l'évaluation des territoires associés. Pour plus d'informations, consultez la publication Prises en charge Any/All dans WCF Data Services.
Tri
Les exemples suivants illustrent des requêtes équivalentes qui trient les données retournées par nom de société, code postal et ordre descendant :
Utilisation de la syntaxe de requête LINQ :
Dim sortedCustomers = From c In context.Customers Order By c.CompanyName Ascending, c.PostalCode Descending Select c
var sortedCustomers = from c in context.Customers orderby c.CompanyName ascending, c.PostalCode descending select c;
Utilisation des méthodes de requête LINQ :
Dim sortedCustomers = context.Customers.OrderBy(Function(c) c.CompanyName) _ .ThenByDescending(Function(c) c.PostalCode)
var sortedCustomers = context.Customers.OrderBy(c => c.CompanyName) .ThenByDescending(c => c.PostalCode);
Option $orderby de la chaîne de requête d'URI :
Dim sortedCustomers = context.Customers _ .AddQueryOption("$orderby", "CompanyName, PostalCode desc")
var sortedCustomers = context.Customers .AddQueryOption("$orderby", "CompanyName, PostalCode desc");
Tous les exemples précédents sont traduits dans l'URI de requête : https://localhost:12345/northwind.svc/Customers()?$orderby=CompanyName,PostalCode desc.
Projection
Les exemples suivants illustrent des requêtes équivalentes qui projettent les données retournées dans le type plus restreint CustomerAddress.
Utilisation de la syntaxe de requête LINQ :
Dim projectedQuery = From c In context.Customers Select New CustomerAddress With { .CustomerID = c.CustomerID, .Address = c.Address, .City = c.City, .Region = c.Region, .PostalCode = c.PostalCode, .Country = c.Country }
var projectedQuery = from c in context.Customers select new CustomerAddress { CustomerID = c.CustomerID, Address = c.Address, City = c.City, Region = c.Region, PostalCode = c.PostalCode, Country = c.Country };
Utilisation des méthodes de requête LINQ :
Dim projectedQuery = context.Customers.Where(Function(c) c.Country = "Germany") _ .Select(Function(c) New CustomerAddress With { .CustomerID = c.CustomerID, .Address = c.Address, .City = c.City, .Region = c.Region, .PostalCode = c.PostalCode, .Country = c.Country })
var projectedQuery = context.Customers.Where(c => c.Country == "Germany") .Select(c => new CustomerAddress { CustomerID = c.CustomerID, Address = c.Address, City = c.City, Region = c.Region, PostalCode = c.PostalCode, Country = c.Country});
Notes
L'option de requête $select ne peut pas être ajoutée à un URI de requête à l'aide de la méthode AddQueryOption(String, Object).Nous vous recommandons d'utiliser la méthode LINQ Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) pour que le client génère l'option de requête $select dans l'URI de requête.
Les deux exemples précédents sont traduits dans l'URI de requête : "https://localhost:12345/northwind.svc/Customers()?$filter=Country eq 'GerGerm'&$select=CustomerID,Address,City,Region,PostalCode,Country".
Pagination du client
Les exemples suivants illustrent des requêtes équivalentes qui génèrent une page d'entités de commande triées incluant 25 commandes, en ignorant les 50 premières commandes :
Application des méthodes de requête à une requête LINQ :
Dim pagedOrders = (From o In context.Orders Order By o.OrderDate Descending Select o) _ .Skip(50).Take(25)
var pagedOrders = (from o in context.Orders orderby o.OrderDate descending select o).Skip(50).Take(25);
Options de chaîne de requête d'URI $skip et $top :
Dim pagedOrders = context.Orders _ .AddQueryOption("$orderby", "OrderDate desc") _ .AddQueryOption("$skip", 50) _ .AddQueryOption("$top", 25) _
var pagedOrders = context.Orders .AddQueryOption("$orderby", "OrderDate desc") .AddQueryOption("$skip", 50) .AddQueryOption("$top", 25);
Les deux exemples précédents sont traduits dans l'URI de requête : https://localhost:12345/northwind.svc/Orders()?$orderby=OrderDate desc&$skip=50&$top=25.
Développer
Lorsque vous interrogez un service de données OData, vous pouvez demander que les entités liées à l'entité cible par la requête soient incluses dans le flux retourné. La méthode Expand(String) est appelée sur la DataServiceQuery<TElement> pour l'ensemble d'entités ciblé par la requête LINQ, avec le nom de l'ensemble d'entités relatif fourni sous la forme de paramètre path. Pour plus d'informations, consultez Chargement de contenu différé (WCF Data Services).
Les exemples suivants illustrent les différentes façons d'utiliser la méthode Expand(String) dans une requête :
Dans la syntaxe de requête LINQ :
Dim ordersQuery = From o In context.Orders.Expand("Order_Details") Where o.CustomerID = "ALFKI" Select o
var ordersQuery = from o in context.Orders.Expand("Order_Details") where o.CustomerID == "ALFKI" select o;
Avec les méthodes de requête LINQ :
Dim ordersQuery = context.Orders.Expand("Order_Details") _ .Where(Function(o) o.CustomerID = "ALFKI")
var ordersQuery = context.Orders.Expand("Order_Details") .Where(o => o.CustomerID == "ALFKI");
Les deux exemples précédents sont traduits dans l'URI de requête : https://localhost:12345/northwind.svc/Orders()?$filter=CustomerID eq 'ALFKI'&$expand=Order_Details.
Méthodes LINQ non prises en charge
Le tableau suivant répertorie les classes de méthodes LINQ qui ne sont pas prises en charge et qui ne peuvent pas être incluses dans une requête exécutée sur un service OData :
Type d'opération |
Méthode non prise en charge |
---|---|
Opérateurs de jeu |
Les opérateurs de jeu suivants ne sont pas pris en charge sur un DataServiceQuery<TElement> : |
Opérations de tri |
Les opérateur de tri suivants, qui nécessitent un IComparer<T>, ne sont pas pris en charge sur un DataServiceQuery<TElement> : |
Opérateurs de projection et de filtrage |
Les opérateurs de projection et de filtrage suivants, qui acceptent un argument de position, ne sont pas pris en charge sur DataServiceQuery<TElement> : |
Opérateurs de groupement |
Aucun opérateur de groupement n'est pris en charge sur un DataServiceQuery<TElement>, impliquant ce qui suit : Les opérations de groupement doivent être exécutées sur le client. |
Opérateurs d'agrégation |
Aucune opération d'agrégation n'est prise en charge sur un DataServiceQuery<TElement>, impliquant ce qui suit : Les opérations d'agrégation doivent soit être exécutées sur le client, soit être encapsulées par une opération de service. |
Opérateurs de pagination |
Les opérateur de pagination suivants ne sont pas pris en charge sur un DataServiceQuery<TElement> : Notes Les opérateurs de pagination qui sont exécutés sur une séquence vide retournent la valeur NULL. |
Autres opérateurs |
Les autres opérateur suivants ne sont pas pris en charge sur un DataServiceQuery<TElement> : |
Fonctions d'expression prises en charge
Les méthodes et propriétés CLR (Common-Language Runtime) suivantes sont prises en charge car elles peuvent être traduites dans une expression de requête et incluses dans l'URI de la requête exécutée sur un service OData :
String Membre |
Fonction OData prise en charge |
---|---|
string concat(string p0, string p1) |
|
bool substringof(string p0, string p1) |
|
bool endswith(string p0, string p1) |
|
int indexof(string p0, string p1) |
|
int length(string p0) |
|
string replace(string p0, string find, string replace) |
|
string substring(string p0, int pos) |
|
string substring(string p0, int pos, int length) |
|
string tolower(string p0) |
|
string toupper(string p0) |
|
string trim(string p0) |
DateTime Membre1 |
Fonction OData prise en charge |
---|---|
int day(DateTime p0) |
|
int hour(DateTime p0) |
|
int minute(DateTime p0) |
|
int month(DateTime p0) |
|
int second(DateTime p0) |
|
int year(DateTime p0) |
1Les propriétés de date et heure équivalentes de Microsoft.VisualBasic.DateAndTime, tout comme la méthode DatePart dans Visual Basic, sont également prises en charge.
Membre Math |
Fonction OData prise en charge |
---|---|
decimal ceiling(decimal p0) |
|
double ceiling(double p0) |
|
decimal floor(decimal p0) |
|
double floor(double p0) |
|
decimal round(decimal p0) |
|
double round(double p0) |
Membre Expression |
Fonction OData prise en charge |
---|---|
bool isof(type p0) |
Le client peut également être en mesure d'évaluer les fonctions CLR supplémentaires sur le client. Une exception NotSupportedException est levée pour toute expression qui ne peut pas être évaluée sur le client ou traduite dans un URI de requête valide pour l'évaluation sur le serveur.
Conditions requises pour le contrôle de version
La prise en charge de LINQ nécessite les conditions du contrôle de version du protocole OData suivantes :
- La prise en charge des opérateurs All<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) et Any<TSource>(IEnumerable<TSource>) requiert que le client et le service de données prennent en charge les versions 3.0 et ultérieures du protocole OData.
Pour plus d'informations, consultez Contrôle de version d'un service de données (WCF Data Services).
Voir aussi
Concepts
Interrogation du service de données (WCF Data Services)
Projections de requête (WCF Data Services)
Matérialisation d'objets (WCF Data Services)