Partager via


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> :

  1. Empty<TResult>

  2. Range

  3. Repeat<TResult>

  4. ToDictionary

  5. ToLookup

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

Concat

string concat(string p0, string p1)

Contains

bool substringof(string p0, string p1)

EndsWith

bool endswith(string p0, string p1)

IndexOf

int indexof(string p0, string p1)

Length

int length(string p0)

Replace

string replace(string p0, string find, string replace)

Substring

string substring(string p0, int pos)

Substring

string substring(string p0, int pos, int length)

ToLower

string tolower(string p0)

ToUpper

string toupper(string p0)

Trim

string trim(string p0)

DateTime Membre1

Fonction OData prise en charge

Day

int day(DateTime p0)

Hour

int hour(DateTime p0)

Minute

int minute(DateTime p0)

Month

int month(DateTime p0)

Second

int second(DateTime p0)

Year

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

Ceiling

decimal ceiling(decimal p0)

Ceiling

double ceiling(double p0)

Floor

decimal floor(decimal p0)

Floor

double floor(double p0)

Round

decimal round(decimal p0)

Round

double round(double p0)

Membre Expression

Fonction OData prise en charge

TypeIs

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 :

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)

Autres ressources

OData : Conventions d'URI