Condividi tramite


Considerazioni su LINQ (WCF Data Services)

In questo argomento vengono fornite informazioni sulla modalità con cui le query LINQ vengono composte ed eseguite quando si utilizza il client WCF Data Services e sulle limitazioni dell'utilizzo di LINQ per eseguire una query su un servizio dati che implementa OData (Open Data Protocol). Per ulteriori informazioni su lla composizione ed esecuzione di query per un servizio dati basato su OData, vedere Esecuzione di query sul servizio dati (WCF Data Services).

Di seguito sono elencate le diverse sezioni di questo argomento:

Composizione di query LINQ

LINQ consente di comporre query per una raccolta di oggetti che implementa IEnumerable<T>. La finestra di dialogo Aggiungi riferimento al servizio in Visual Studio e lo strumento DataSvcUtil.exe sono utilizzati per generare la rappresentazione di un servizio OData come classe di contenitore di entità che eredita da DataServiceContext e gli oggetti che rappresentano le entità restituite nei feed. Questi strumenti generano anche le proprietà per la classe contenitore di entità delle raccolte esposte come feed dal servizio. Ognuna di queste proprietà della classe che incapsula il servizio dati restituisce un elemento DataServiceQuery<TElement>. Dal momento che la classe DataServiceQuery<TElement> implementa l'interfaccia IQueryable<T> definita da LINQ, è possibile comporre una query LINQ per i feed esposti dal servizio dati che vengono convertiti dalla libreria client in un URI di richiesta query inviato al servizio dati in esecuzione.

Importante

La sintassi LINQ consente di esprimere un set di query più ampio di quello consentito dalla sintassi URI utilizzata dai servizi dati OData.Quando non è possibile eseguire il mapping della query a un URI nel servizio dati di destinazione, viene generato un oggetto NotSupportedException.Per ulteriori informazioni, vedere la sezione Unsupported LINQ Methods in questo argomento.

Nell'esempio seguente viene riportata una query LINQ che restituisce gli elementi Orders con un costo di spedizione maggiore di 30 dollari e ordina i risultati in base alla data di spedizione, partendo da quella più recente:

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;

Questa query LINQ viene convertita nel seguente URI di query che viene eseguito sul servizio dati Guida rapida basato su Northwind:

https://localhost:12345/Northwind.svc/Orders?Orderby=ShippedDate&?filter=Freight gt 30

Per informazioni generali su LINQ, vedere Language-Integrated Query (LINQ).

LINQ consente di comporre query tramite la sintassi di query dichiarativa specifica della lingua, mostrata nell'esempio precedente, e un set di metodi di query noti come operatori di query standard. Una query equivalente a quella dell'esempio precedente può essere composta solo tramite la sintassi basata sul metodo, come indicato nell'esempio seguente:

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);

Il client WCF Data Services è in grado di convertire entrambi tipi di query composte in un URI di query ed è possibile estendere una query LINQ aggiungendo i metodi di query a un'espressione di query. Quando si compongono query LINQ aggiungendo la sintassi del metodo a un'espressione di query o un elemento DataServiceQuery<TElement>, le operazioni vengono aggiunte all'URI della query nell'ordine di chiamata dei metodi. Equivale alla chiamata del metodo AddQueryOption(String, Object) per aggiungere ogni opzione di query all'URI della query.

Esecuzione di query LINQ

Alcuni metodi di query LINQ, ad esempio First<TSource> o Single<TSource>, quando vengono aggiunti alla query ne causano l'esecuzione. Una query viene eseguita anche quando i risultati vengono enumerati in modo implicito, ad esempio durante un ciclo foreach o quando la query è assegnata a una raccolta List. Per ulteriori informazioni, vedere Esecuzione di query sul servizio dati (WCF Data Services).

Il client esegue una query LINQ in due parti. Ogni qualvolta possibile, le espressioni LINQ di una query vengono prima valutate sul client e quindi viene generata una query basata sull'URI che viene inviata al servizio dati per la valutazione rispetto ai dati del servizio. Per ulteriori informazioni, vedere la sezione Client versus Server Execution in Esecuzione di query sul servizio dati (WCF Data Services).

Quando non è possibile convertire una query LINQ in un URI di query conforme a OData, viene generata un'eccezione quando viene tentata l'esecuzione. Per ulteriori informazioni, vedere Esecuzione di query sul servizio dati (WCF Data Services).

Esempi di query LINQ

Negli esempi delle sezioni seguenti vengono illustrati i tipi di query LINQ che possono essere eseguiti su un servizio OData.

Filtro

Negli esempi di query LINQ in questa sezione vengono filtrati i dati nel feed restituito dal servizio.

Negli esempi seguenti vengono illustrate query equivalenti che filtrano le entità Orders restituite in modo che vengano restituiti solo gli ordini con un costo di spedizione maggiore di $30:

  • Uso della sintassi di query 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;
    
  • Uso dei metodi di query LINQ:

    Dim filteredOrders = context.Orders.Where(Function(o) o.Freight.Value > 0)
    
    var filteredOrders = context.Orders
        .Where(o => o.Freight > 30);
    
  • Opzione $filter della stringa di query:

    ' 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");
    

Tutti gli esempi precedenti vengono convertiti nell'URI di query: https://localhost:12345/northwind.svc/Orders()?$filter=Freight gt 30M.

È inoltre possibile utilizzare gli operatori All<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) e Any<TSource>(IEnumerable<TSource>) per comporre query che filtrano entità in base alle proprietà di una raccolta. In questo caso, il predicato viene valutato rispetto alle proprietà che restituiscono raccolte di entità correlate e raccolte di tipi primitivi e complessi. Ad esempio, la query seguenti restituisce tutti i dipendenti con un territorio, con una descrizione contenente la stringa fornita:

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;

In questa query l'operatore Any<TSource>(IEnumerable<TSource>) consente l'attraversamento dell'associazione molti-a-molti tra Employees e Territories per filtrare i dipendenti in base a una valutazione dei territori correlati. Per ulteriori informazioni, vedere il post Supporto di Any/All in WCF Data Services.

Ordinamento

Negli esempi seguenti vengono illustrate query equivalenti che ordinano i dati restituiti in base al nome dell'azienda e al codice postale, in ordine decrescente:

  • Uso della sintassi di query 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;
    
  • Uso dei metodi di query 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);
    
  • Opzione $orderby della stringa di query:

    Dim sortedCustomers = context.Customers _
                          .AddQueryOption("$orderby", "CompanyName, PostalCode desc")
    
    var sortedCustomers = context.Customers
        .AddQueryOption("$orderby", "CompanyName, PostalCode desc");
    

Tutti gli esempi precedenti vengono convertiti nell'URI di query: https://localhost:12345/northwind.svc/Customers()?$orderby=CompanyName,PostalCode desc.

Proiezione

Negli esempi seguenti vengono illustrate query equivalenti che ordinano i dati restituiti dal progetto nel tipo CustomerAddress più ristretto:

  • Uso della sintassi di query 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
                };
    
  • Uso dei metodi di query 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});                   
    

Nota

L'opzione di query $select non può essere aggiunta a un URI di query tramite il metodo AddQueryOption(String, Object).Si consiglia di utilizzare il metodo LINQ Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) in modo che il client generi l'opzione di query $select nell'URI della richiesta.

Entrambi gli esempi precedenti vengono convertiti nell'URI di query: "https://localhost:12345/northwind.svc/Customers()?$filter=Country eq 'GerGerm'&$select=CustomerID,Address,City,Region,PostalCode,Country".

Paging del client

Negli esempi seguenti vengono illustrate query equivalenti che richiedono una pagina delle entità ordinate che include 25 ordini, ignorando i primi 50 ordini:

  • Applicazione di metodi di query a una query 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);
    
  • Opzioni $skip e $top della stringa di query dell'URI:

    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);
    

Entrambi gli esempi precedenti vengono convertiti nell'URI di query: https://localhost:12345/northwind.svc/Orders()?$orderby=OrderDate desc&$skip=50&$top=25.

Espansione

Quando si esegue una query su un servizio dati OData, è possibile richiedere che le entità relative all'entità di destinazione della query siano incluse nel feed restituito. Il metodo Expand(String) viene chiamato su DataServiceQuery<TElement> per il set di entità indirizzato dalla query LINQ, con il relativo nome del set di entità fornito come parametro path. Per ulteriori informazioni, vedere Caricamento di contenuto posticipato (WCF Data Services).

Negli esempi seguenti vengono mostrate modalità equivalenti per utilizzare il metodo Expand(String) in una query:

  • Nella sintassi della query 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;
    
  • Con i metodi di query 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");
    

Entrambi gli esempi precedenti vengono convertiti nell'URI di query: https://localhost:12345/northwind.svc/Orders()?$filter=CustomerID eq 'ALFKI'&$expand=Order_Details.

Metodi LINQ non supportati

Nella tabella seguente sono riportate le classi dei metodi LINQ non supportati che non possono essere incluse in una query eseguita su un servizio OData:

Tipo di operazione 

Metodo non supportato

Operatori di impostazione

Gli operatori sui set seguenti non sono supportati con DataServiceQuery<TElement>:

Operatori di ordinamento

Gli operatori di ordinamento seguenti che richiedono IComparer<T> non sono supportati con DataServiceQuery<TElement>:

Operatori di proiezione e di filtro

I seguenti operatori di proiezione e filtro che accettano un argomento posizionale non sono supportati con DataServiceQuery<TElement>:

Operatori di raggruppamento

Tutti gli operatori di raggruppamento non sono supportati con DataServiceQuery<TElement>, compresi quelli indicati di seguito:

È necessario eseguire le operazioni di raggruppamento sul client.

Operatori di aggregazione

Tutti gli operatori di aggregazione non sono supportati con DataServiceQuery<TElement>, compresi quelli indicati di seguito:

Le operazioni di aggregazione devono essere eseguite sul client o devono essere incapsulate da un'operazione del servizio.

Operatori di paging

Gli operatori di paging seguenti non sono supportati con DataServiceQuery<TElement>:

Nota

Gli operatori di paging eseguiti in una sequenza vuota restituiscono Null.

Altri operatori

Gli operatori seguenti non sono supportati con DataServiceQuery<TElement>:

  1. Empty<TResult>

  2. Range

  3. Repeat<TResult>

  4. ToDictionary

  5. ToLookup

Funzioni di espressione non supportate

Le proprietà e i metodi Common Language Runtime (CLR) riportati di seguito sono supportati perché possono essere convertiti in un'espressione di query per l'inclusione nell'URI della richiesta a un servizio OData:

Membro String

Funzione OData supportata

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)

Membro1 DateTime

Funzione OData supportata

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)

1In Visual Basic sono supportate anche le proprietà equivalenti di data e ora di Microsoft.VisualBasic.DateAndTime, nonché il metodo DatePart.

Membro Math

Funzione OData supportata

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)

Membro Expression

Funzione OData supportata

TypeIs

bool isof(type p0)

È possibile che il client sia anche in grado di valutare funzioni CLR aggiuntive sul client. Viene generata un'eccezione NotSupportedException per qualsiasi espressione che non può essere valutata sul client e non può essere convertita in un URI della richiesta valido per la valutazione sul server.

Requisiti di versione

Il supporto LINQ prevede i seguenti requisiti di versione del protocollo OData:

Per ulteriori informazioni, vedere Controllo delle versioni del servizio dati (WCF Data Services).

Vedere anche

Concetti

Esecuzione di query sul servizio dati (WCF Data Services)

Proiezioni di query (WCF Data Services)

Materializzazione di oggetti (WCF Data Services)

Altre risorse

OData: convenzioni URI