2010-06-08 72 views
8

Các mã sau đây:LINQ to SQL - Tại sao bạn không thể sử dụng WHERE sau khi 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)); 
} 

mang lại cho tôi những lỗi sau:

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

Tôi cố định các lỗi bằng cách làm như sắp xếp ở cuối:

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

Nhưng tôi tự hỏi tại sao giới hạn này lại được áp dụng? Lý do API được thiết kế sao cho bạn không thể thêm ràng buộc where sau khi sử dụng toán tử order by?

Trả lời

12

Kiểu trả về của OrderByIOrderedQueryable<T>, vì vậy đó là kiểu của orders biến (một phần vì bạn có một dự báo không-op ở cuối) - nhưng kiểu trả về của Where chỉ IQueryable<T> là. Về cơ bản, bạn có một hỗn hợp của một phép chiếu không có biến cục bộ được nhập hoàn toàn phần hoạt động cuối cùng của truy vấn là đặt hàng, bạn sẽ muốn gán lại biến. Đó là một sự kết hợp không vui, về cơ bản.

Bạn có thể sửa chữa nó như thế này:

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

Ngoài ra, nếu bạn thực hiện các dự báo không-op một cách rõ ràng bằng ký hiệu dấu chấm (tôi nghi ngờ người dịch SQL sẽ đủ thông minh để đối phó!) Những suy luận kiểu sẽ không sao đâu:

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

Hoặc như một gợi ý thức và hơi kỳ quặc, bạn chỉ có thể thay đổi thứ tự ban đầu của bạn whereorderby khoản. Đây sẽ là một ý tưởng tồi trong LINQ to Objects, nhưng không nên tạo sự khác biệt trong 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)); 
} 

Bây giờ, trong điều khoản của "tại sao" của API thiết kế: OrderByOrderByDescending trở nên IOrderedQueryable sau đó bạn có thể kết nối nó với ThenByThenByDescending dựa vào việc có thứ tự hiện có mà chúng có thể trở thành thứ yếu, nếu bạn hiểu ý tôi.

+0

một truy vấn không-op là gì? – MCS

+0

Đây là một câu trả lời thực sự toàn diện và là một lời giải thích tuyệt vời. Cảm ơn. – MCS

+0

@MCS: Tôi có nghĩa là một phép chiếu không có - một mệnh đề lựa chọn chỉ chọn những gì đã có, nếu bạn hiểu ý tôi. –

4

Điều quan trọng cần lưu ý là var được nhập mạnh và được giải thích tại thời gian biên dịch. Đoạn mã đầu tiên của bạn về bản chất giống như sau:

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

Khi bạn viết mã theo cách này, bạn không thể gán IQueryable cho biến được khai báo là IOrderedQueryable.

Bạn không thể nghĩ ra var trong cùng một cách bạn sẽ phản đối

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

Các vấn đề liên quan