2010-06-08 11 views
8

El siguiente código:LINQ to SQL - ¿Por qué no puede usar un WHERE después de un ORDER BY?

// select all orders 
var orders = from o in FoodOrders 
      where o.STATUS = 1 
      order by o.ORDER_DATE descending 
      select o; 

// if customer id is specified, only select orders from specific customer 
if (customerID!=null) 
{ 
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID)); 
} 

me da el siguiente error:

Cannot implicitly convert type 'System.Linq.IQueryable' to 'System.Linq.IOrderedQueryable'. An explicit conversion exists (are you missing a cast?)

He arreglado el error al hacer la clasificación al final:

// select all orders 
var orders = from o in FoodOrders 
      where o.STATUS = 1 
      select o; 

// if customer id is specified, only select orders from specific customer 
if (customerID!=null) 
{ 
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID)); 
} 

// I'm forced to do the ordering here 
orders = orders.OrderBy(o => o.ORDER_DATE).Reverse(); 

Pero me pregunto ¿Por qué esta limitación está en su lugar? ¿Cuál es la razón por la que la API se diseñó de tal manera que no se puede agregar una restricción where después de usar un operador order by?

Respuesta

12

El tipo de retorno de OrderBy es IOrderedQueryable<T>, por lo que es el tipo de la variable orders (en parte porque tiene una proyección no-op al final) - pero el tipo de retorno de Where es sólo IQueryable<T>. Básicamente tienes una mezcla de una proyección no-op y una variable local implícitamente escrito y la última parte activa de la consulta es un ordenamiento, y que está a continuación, con ganas de volver a asignar la variable. Es una combinación infeliz, básicamente.

Se podría fijar de esta manera:

IQuerable<FoodOrders> orders = from o in FoodOrders 
           where o.STATUS == 1 
           order by o.ORDER_DATE descending 
           select o; 

// if customer id is specified, only select orders from specific customer 
if (customerID!=null) 
{ 
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID)); 
} 

Por otra parte, si se realiza la proyección no-op explícitamente el uso de la notación de puntos (sospecho que el traductor SQL será lo suficientemente inteligente como para hacer frente!) La inferencia de tipos haría estar bien:

var orders = FoodOrders.Where(o => o.STATUS == 1) 
         .OrderByDescending(o => o.ORDER_DATE) 
         .Select(o => o); 

// if customer id is specified, only select orders from specific customer 
if (customerID!=null) 
{ 
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID)); 
} 

O como una sugerencia final y un poco rara, sólo podría cambiar el orden de sus iniciales where y orderby cláusulas. Esto sería una mala idea en LINQ a objetos, pero no debe hacer una diferencia en LINQ a SQL:

var orders = from o in FoodOrders 
      order by o.ORDER_DATE descending 
      where o.STATUS == 1 
      select o; 

// if customer id is specified, only select orders from specific customer 
if (customerID!=null) 
{ 
    orders = orders.Where(o => customerID.Equals(o.CUSTOMER_ID)); 
} 

Ahora, en términos de "qué" de la API de diseño: OrderBy y OrderByDescending retorno IOrderedQueryable por lo que luego puede encadenarlo con ThenBy y ThenByDescending que dependen de que haya un pedido existente al que puedan llegar a ser secundarios, si entiende lo que quiero decir.

+0

¿Qué es una consulta no-op? – MCS

+0

Esta es una respuesta realmente minuciosa y una gran explicación. Gracias. – MCS

+0

@MCS: Quise decir una proyección no operativa, una cláusula de selección que solo selecciona lo que ya está allí, si entiendes lo que quiero decir. –

4

Es importante tener en cuenta que var está fuertemente tipado y se interpreta en tiempo de compilación. Su primer fragmento de código que, esencialmente, el mismo que:

IOrderedQueryable<FoodOrders> orders = from o in FoodOrders 
     where o.STATUS = 1 
     order by o.ORDER_DATE descending 
     select o; 

Cuando se escribe el código de esta manera se hace evidente por qué no puede asignar una IQueryable a una variable declarada como IOrderedQueryable.

No se puede pensar en var de la misma manera que se opondría

object aString = "Testing..."; 
var bString = "Testing..."; 

aString = 1; // Works 
bString = 1; // Fails because 1 is not a string 

http://msdn.microsoft.com/en-us/library/bb384061.aspx