Compartir a través de


Consideraciones sobre LINQ (WCF Data Services)

En este tema se proporciona información sobre cómo se crean y ejecutan consultas LINQ cuando se usa el cliente Servicios de datos de Microsoft WCF y las limitaciones de uso de LINQ para consultar un servicio de datos que implementa Open Data Protocol (OData). Para obtener más información sobre cómo se crean y ejecutan consultas en un servicio de datos basado en OData, vea Consultar el servicio de datos (WCF Data Services).

Este tema contiene las siguientes secciones:

Redactar consultas LINQ

LINQ permite redactar consultas en una colección de objetos que implemente la interfaz IEnumerable<T>. Tanto el cuadro de diálogo Agregar referencia de servicio de Visual Studio como la herramienta DataSvcUtil.exe se usan para generar una representación de un servicio de OData como clase de contendor de entidades que hereda de la clase DataServiceContext, así como objetos que representen las entidades devueltas en fuentes. Estas herramientas también generan propiedades en la clase de contenedor de entidades de las colecciones que el servicio exponen como fuentes. Cada una de estas propiedades de la clase que encapsula el servicio de datos devuelve una clase DataServiceQuery<TElement>. Puesto que la clase DataServiceQuery<TElement> implementa la interfaz IQueryable<T> definida por LINQ, puede crear una consulta LINQ en fuentes expuestas por el servicio de datos, que la biblioteca cliente traduce en un URI de solicitud de consulta que se envía al servicio de datos en la ejecución.

Importante

El conjunto de consultas que se pueden expresar en la sintaxis de LINQ es más amplio que los habilitados en la sintaxis URI basada en OData que usan los servicios de datos.Cuando la consulta no se puede asignar a ningún URI del servicio de datos de destino, se produce una excepción NotSupportedException.Para obtener más información, vea Unsupported LINQ Methods en este tema.

El siguiente ejemplo es una consulta LINQ que devuelve Orders con un costo de flete de más de 30 $ y ordena los resultados por la fecha de envío, comenzando por la fecha de envío más reciente:

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;

Esta consulta LINQ se traduce en el siguiente URI de la consulta que se ejecuta en el servicio de base de datos del tutorial rápido basado en Northwind:

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

Para obtener más información general acerca de LINQ, vea Language-Integrated Query (LINQ).

LINQ permite redactar consultas mediante el uso tanto de la sintaxis de consulta declarativa específica del lenguaje, mostrada en el ejemplo anterior, como de un conjunto de métodos de consulta denominados operadores de consulta estándar. Una consulta equivalente al ejemplo anterior se puede redactar mediante el uso de la sintaxis basada en métodos únicamente, como se muestra en el siguiente ejemplo:

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

El cliente de Servicios de datos de Microsoft WCF puede traducir ambos tipos de consultas redactadas en un URI de la consulta y puede ampliar una consulta LINQ si anexa los métodos de consulta a una expresión de consulta. Cuando redacte consultas LINQ anexando la sintaxis del método a una expresión de consulta o a una clase DataServiceQuery<TElement>, las operaciones se agregan al URI de la consulta en el orden en el que se llama a los métodos. Esto es equivalente a llamar al método AddQueryOption(String, Object) para agregar cada opción de consulta al URI de la consulta.

Ejecutar consultas LINQ

Ciertos métodos de consulta LINQ, como los métodos First<TSource> o Single<TSource>, cuando se anexan a la consulta, provocan la ejecución de esta. También se ejecuta una consult6a cuando los resultados se enumeran implícitamente, como durante un bucle foreach o cuando la consulta se asigna a una colección List. Para obtener más información, vea Consultar el servicio de datos (WCF Data Services).

El cliente ejecuta una consulta LINQ en dos partes. Siempre que sea posible, las expresiones LINQ de una consulta primero se evalúan en el cliente y, a continuación, se generan y se envían al servicio de datos para su evaluación en los datos del servicio. Para obtener más información, vea la sección Client versus Server Execution de Consultar el servicio de datos (WCF Data Services).

Cuando no se puede traducir ninguna consulta LINQ de un URI de consulta conforme a OData, se produce una excepción al intentar la ejecución. Para obtener más información, vea Consultar el servicio de datos (WCF Data Services).

Ejemplos de consultas LINQ

Los ejemplos de las secciones siguientes muestran los tipos de consultas LINQ que se pueden ejecutar en un servicio de OData.

Filtrar

Los ejemplos de consultas LINQ de esta sección filtran los datos de la fuente devuelta por el servicio.

Los siguientes ejemplos son consultas equivalentes que filtran las entidades Orders devueltas para que solo se devuelvan los pedidos con un costo de flete mayor que 30 $:

  • Usar sintaxis de consulta 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;
    
  • Usar métodos de consulta LINQ:

    Dim filteredOrders = context.Orders.Where(Function(o) o.Freight.Value > 0)
    
    var filteredOrders = context.Orders
        .Where(o => o.Freight > 30);
    
  • La opción $filter de la cadena de consulta del 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");
    

Todos los ejemplos anteriores se traducen en el URI de consulta: https://localhost:12345/northwind.svc/Orders()?$filter=Freight gt 30M.

También puede usar los operadores All<TSource>(IEnumerable<TSource>, Func<TSource, Boolean>) y Any<TSource>(IEnumerable<TSource>) para crear consultas que filtren entidades basándose en propiedades de colección. En este caso, el predicado se evalúa con respecto a propiedades que devuelven tanto colecciones de entidades relacionadas como colecciones de tipos primitivos y complejos. Por ejemplo, la consulta siguiente devuelve todos los empleados que tengan un territorio cuya descripción contenga la cadena proporcionada:

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;

En esta consulta, el operador Any<TSource>(IEnumerable<TSource>) le permite recorrer la asociación varios a varios entre Employees y Territories para filtrar empleados según la evaluación de los territorios relacionados. Para obtener más información, vea la entrada de blog Compatibilidad con Any/All en WCF Data Services.

Ordenar

Los siguientes ejemplos muestran consultas equivalentes que ordenan ascendentemente los datos tanto por nombre de compañía como por código postal:

  • Usar sintaxis de consulta 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;
    
  • Usar métodos de consulta 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);
    
  • Opción $orderby de la cadena de consulta del URI):

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

Todos los ejemplos anteriores se traducen en el URI de la consulta: https://localhost:12345/northwind.svc/Customers()?$orderby=CompanyName,PostalCode desc.

Proyección

Los siguientes ejemplos muestran las consultas equivalentes que proyectan los datos devueltos en el tipo CustomerAddress más restringido:

  • Usar sintaxis de consulta 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
                };
    
  • Usar métodos de consulta 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

La opción de consulta $select no se puede agregar a ningún URI de la consulta mediante el uso del método AddQueryOption(String, Object).Se recomienda usar el método Select<TSource, TResult>(IEnumerable<TSource>, Func<TSource, TResult>) de LINQ para que el cliente genere la opción de consulta $select en el URI de solicitud.

Los dos ejemplos anteriores se traducen en el URI de la consulta: "https://localhost:12345/northwind.svc/Customers()?$filter=Country eq 'GerGerm'&$select=CustomerID,Address,City,Region,PostalCode,Country".

Paginación del cliente

En los siguientes ejemplos se muestran las consultas equivalentes que solicita una página de las entidades de pedidos ordenados que incluye 25 pedidos, omitiendo los 50 primeros pedidos:

  • Aplicar métodos de consulta a una consulta 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);
    
  • opciones $skip y $top de cadena de consulta de 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);
    

Los dos ejemplos anteriores se traducen en el URI de la consulta: https://localhost:12345/northwind.svc/Orders()?$orderby=OrderDate desc&$skip=50&$top=25.

Expandir

Cuando se carga un servicio de datos de OData, puede solicitar que las entidades relacionadas con la entidad que sea el destino de la consulta se incluyan en la fuente devuelta. Se llama al método Expand(String) en la clase DataServiceQuery<TElement> para el conjunto de entidades que sean el destino de la consulta LINQ, con el nombre del conjunto de entidades relacionado proporcionado como el parámetro path. Para obtener más información, vea Cargar contenido aplazado (WCF Data Services).

En los siguientes ejemplos se muestran las formas equivalentes de usar el método Expand(String) en una consulta:

  • En la sintaxis de las consultas 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 los métodos de consulta 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");
    

Los dos ejemplos anteriores se traducen en el URI de la consulta: https://localhost:12345/northwind.svc/Orders()?$filter=CustomerID eq 'ALFKI'&$expand=Order_Details.

Métodos LINQ no admitidos

La siguiente tabla contiene las clases de métodos LINQ que no se admiten y que no se pueden incluir en una consulta ejecutada en un servicio de OData:

Tipo de operación 

Métodos no admitidos

Operadores de conjuntos

No se admiten los siguientes operadores de conjuntos en DataServiceQuery<TElement>:

Operaciones de ordenación

No se admiten los siguientes operadores de ordenación que requieran la interfaz IComparer<T> en una clase DataServiceQuery<TElement>:

Métodos de proyección y filtrado

No se admiten ninguno de los siguientes operadores de proyección y filtrado que acepten un argumento posicional en una clase DataServiceQuery<TElement>:

Operadores de agrupación

No se admite ningún operador de agrupación en una clase DataServiceQuery<TElement>, que incluya lo siguiente:

Los operadores de agrupación se deben ejecutar en el cliente.

Operadores de agregación

No se admite ninguna operación de agregado en una clase DataServiceQuery<TElement>, que incluya lo siguiente:

Las operaciones de agregado se deben ejecutar en el cliente o las debe encapsular una operación de servicio.

Operadores de paginación

No se admiten los siguientes operadores de paginación en una clase DataServiceQuery<TElement>:

Nota

Los operadores de paginación que se ejecuten en una secuencia vacía devuelven NULL.

Operadores adicionales

No se admiten los siguientes operadores adicionales en una clase DataServiceQuery<TElement>:

  1. Empty<TResult>

  2. Range

  3. Repeat<TResult>

  4. ToDictionary

  5. ToLookup

Funciones de expresión admitidas

Se admiten los siguientes métodos y propiedades de Common Language Runtime (CLR) porque se pueden traducir en una expresión de consulta para su inclusión en el URI de solicitud en un servicio de OData:

Miembro de la clase String

Función de OData admitida

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)

Miembro de la estructura DateTime1

Función de OData admitida

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)

1Las propiedades de fecha y hora equivalentes de la clase Microsoft.VisualBasic.DateAndTime, así como el método DatePart de Visual Basic también se admiten.

Miembro de Math

Función de OData admitida

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)

Miembro de Expression

Función de OData admitida

TypeIs

bool isof(type p0)

Además, el cliente quizá pueda evaluar las funciones CLR adicionales en el cliente. Se produce una excepción NotSupportedException para cualquier expresión que no se pueda evaluar en el cliente y que no se pueda traducir en un URI de solicitud válido para su evaluación en el servidor.

Requisitos de control de versiones

La compatibilidad con LINQ tiene los siguientes requisitos de versiones del protocolo OData:

Para obtener más información, vea Control de versiones del servicio de datos (Servicios de datos de Microsoft WCF).

Vea también

Conceptos

Consultar el servicio de datos (WCF Data Services)

Proyecciones de consultas (WCF Data Services)

Materialización de objetos (WCF Data Services)

Otros recursos

OData: convenciones de URI