2010-06-08 9 views
8

Poniższy kod:LINQ to SQL - Dlaczego nie możesz użyć WHERE po 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)); 
} 

daje mi następujący błąd:

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

Naprawiłem błąd wykonując sortowania na końcu:

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

Ale zastanawiam dlaczego to ograniczenie obowiązuje? Z jakiego powodu API został zaprojektowany w taki sposób, że nie można dodać ograniczenia where po użyciu operatora order by?

Odpowiedz

12

Rodzaj powrót OrderBy jest IOrderedQueryable<T>, więc to jest typ orders zmiennej (częściowo dlatego, że masz projekcję no-op na końcu) - ale typ powrót Where tylko IQueryable<T>. Zasadniczo masz mieszankę nieoptymalnej projekcji i niejawnie wpisaną zmienną lokalną i ostatnią aktywną częścią zapytania jest uporządkowanie, i, które chcesz zmienić. Zasadniczo jest to nieszczęśliwa kombinacja.

Można go naprawić tak:

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

Ewentualnie, jeśli wykonywana projekcja no-op jawnie przy użyciu notacji kropki (podejrzewam SQL tłumacz będzie wystarczająco silny, aby poradzić sobie!) Rodzaju wnioskowanie byłoby być w porządku:

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

lub jako ostatecznej i nieco dziwnym sugestii, można po prostu zmienić kolejność początkowych where i orderby klauzul. Byłby to zły pomysł w LINQ do obiektów, ale nie powinny mieć znaczenie w LINQ to 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)); 
} 

Teraz, jeśli chodzi o „dlaczego” API wzorem: OrderBy i OrderByDescending powrotnej IOrderedQueryable tak możesz je połączyć łańcuchem z ThenBy i ThenByDescending, które polegają na istniejącym porządku, w którym mogą stać się wtórne, jeśli widzisz co mam na myśli.

+0

Co to jest kwerenda no-op? – MCS

+0

To jest naprawdę dokładna odpowiedź i świetne wyjaśnienie. Dzięki. – MCS

+0

@MCS: Miałem na myśli projekcję bez opozycji - klauzulę wyboru, która po prostu wybiera to, co już jest, jeśli widzisz, co mam na myśli. –

4

Należy zauważyć, że var jest silnie typowany i interpretowany podczas kompilacji. Twój pierwszy kod snippet to zasadniczo taka sama, jak:

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

Kiedy napisać kod w ten sposób staje się oczywiste, dlaczego nie można przypisać do zmiennej IQueryable zadeklarowanej jako IOrderedQueryable.

Nie można myśleć var ​​w taki sam sposób, byś sprzeciw

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