2011-12-14 27 views
20

Có cách nào để biết liệu một IQueryable<T> đã được đặt hàng hay chưa (sử dụng OrderBy hoặc OrderbyDescending)?Xác định xem một IQueryable <T> đã được đặt hàng hay không

Vì vậy, tôi biết nên gọi số OrderBy hoặc ThenBy trên bộ sưu tập.

IQueryable<Contact> contacts = Database.GetContacts(); 

Tôi đã thử contacts is IOrderedQueryable<Contact>, nhưng điều đó luôn đúng.

Chỉnh sửa: Tôi vừa thay đổi ví dụ của mình, ví dụ trước không thực sự hiển thị quan điểm của tôi. Giả sử rằng GetContacts sử dụng Entity Framework và chỉ cần trả về tất cả các bản ghi của bảng.

Sau đó, tôi áp dụng một số chức năng cho contacts, tôi không có kiến ​​thức về những chức năng đó. Họ có thể sắp xếp hoặc lọc IQueryable<Contact>.

Khi tôi lấy lại bộ sưu tập, tôi cần sắp xếp lại một lần nữa. Để làm như vậy, tôi cần biết liệu tôi có cần gọi số OrderBy hoặc ThenBy hay không. Vì vậy, tôi không sắp xếp lại toàn bộ bộ sưu tập nếu nó đã được sắp xếp.

+0

Nếu bạn đang ở trong lĩnh vực của 'IQueryable', bạn cần phải lo lắng? Ý tôi là, một '.OrderBy' bổ sung cũng có thể dẫn đến không thay đổi những gì thực sự được thực thi bởi nhà cung cấp trên nguồn dữ liệu cơ bản. – AakashM

+0

@AakashM, Nếu tôi gọi 'OrderBy' trên một 'IQueryable' đã được sắp xếp, tôi sẽ mất loại đó. Tôi chỉ muốn thêm vào nó. –

+0

Tôi đã thực sự nghĩ rằng bạn đang lo lắng về perf. Làm thế nào về luôn luôn sử dụng 'ThenBy'? – AakashM

Trả lời

2

Câu trả lời ngắn gọn là không, lớp có thể truy vấn không duy trì cờ hoặc liệu bộ sưu tập có được sắp xếp hay không và phương pháp nào có thể đã được sử dụng để thực hiện sắp xếp như vậy.

http://msdn.microsoft.com/en-us/library/system.linq.queryable.aspx

+7

Sau đó, cách ['.Skip'] (http://msdn.microsoft.com/en-us/library/bb357513.aspx) có thể [ném một ngoại lệ] (http://stackoverflow.com/questions/ 225481/how-to-check-cho-the-sự hiện diện-of-an-orderby-in-a-objectqueryt-expression-tree) khi bạn sử dụng nó trên một bộ sưu tập EF không có thứ tự? –

+1

Tôi không nghĩ .Skip không ném ngoại lệ. Nhà cung cấp tiềm ẩn ném ra một ngoại lệ khi nó cố gắng xây dựng một truy vấn từ toàn bộ * IQueryable. –

+1

Đúng là không có lá cờ như vậy, nhưng có thể biết liệu một phương thức đặt hàng đã được gọi hay chưa. Xem [câu trả lời của tôi] (http://stackoverflow.com/a/31252271/964514). –

1

Bạn sẽ không bao giờ biết các đối tượng đã được đặt hàng đúng cách hay chưa, trừ khi bạn tự kiểm tra đặt hàng. Ví dụ của bạn rất dễ thấy chúng không được sắp xếp, bởi vì các số có thứ tự tự nhiên, nhưng IQueryable là một generic, có nghĩa là nó có thể xử lý các loại đối tượng khác nhau. Thứ tự của các đối tượng người dùng nói (FirstName, LastName, DateStart và LastPayDate) có một thứ tự tùy ý, và do đó thứ tự chúng được trả về không nhất thiết là thứ tự bạn đang tìm kiếm. (Mà được coi là lĩnh vực chính cho các loại? Nó phụ thuộc vào nhu cầu của bạn.) Vì vậy, trong lý thuyết, câu hỏi, "Họ đã ra lệnh" luôn luôn có thể là "Có!" Thứ tự bạn đang tìm kiếm có thể cực kỳ khác với thứ mà hệ thống trả về.

+0

Ví dụ của tôi là chỉ ra rằng thử nghiệm với 'IOrderedQueryable' luôn trả về giá trị true. Tôi sẽ làm rõ câu hỏi của tôi. –

1

Thực ra, bạn có thể.

Vấn đề đầu tiên tôi thấy trong mã của bạn là bạn đang truyền bộ sưu tập đến IQueryable mà không có bất kỳ lý do nào để làm như vậy.

Đoạn sau đây:

var numbers = new[] {1, 5, 6, 87, 3}; 
Console.Write(numbers is IOrderedEnumerable<int>); 
var ordered = numbers.OrderBy(c => c); 
Console.Write(ordered is IOrderedEnumerable<int>); 

Có thậm chí không cần phải được chạy: kiểm tra đầu tiên sẽ cho bạn một thời gian thiết kế cảnh báo nói rằng biểu thức này sẽ không bao giờ thành sự thật.

Dù sao, nếu bạn chạy nó, nó sẽ cung cấp cho bạn False cho lần kiểm tra đầu tiên và True cho lần kiểm tra thứ hai.

Bạn có thể làm điều tương tự với IQueryable<T>IOrderedQueryable<T> cung cấp bạn đang thực sự sử dụng loại đó và không truyền một bộ sưu tập cho nó.

+0

Điều gì sẽ xảy ra nếu các mục trong danh sách xảy ra đã được sắp xếp theo thứ tự? –

+3

Điều này dường như không hoạt động trên một bộ sưu tập như 'dbSet.AsQueryable()' vì điều này sẽ luôn trả về true trên kiểm tra 'là IOrderedQueryable'. – Juri

1

Bạn có thể kiểm tra ToString() truy vấn của mình để tìm hiểu xem Order By có được sử dụng hay không.

Khi tham gia xảy ra, ToString của IQueryable đặt các dấu ngoặc vào đầu và cuối của truy vấn bên trong.Vì vậy, nếu bạn tìm thấy các dấu ngoặc đóng cuối cùng, bạn có thể kiểm tra xem truy vấn nhiều nhất bên ngoài của bạn có mệnh đề Order By hay không.

private bool isOrdered(IQueryable Data) 
    { 
     string query = Data.ToString(); 

     int pIndex = query.LastIndexOf(')'); 

     if (pIndex == -1) 
      pIndex = 0; 

     if (query.IndexOf("ORDER BY", pIndex) != -1) 
     { 
      return true; 
     } 

     return false; 
    } 

Tôi biết nó cực kỳ bẩn nhưng nó hoạt động trong tất cả các trường hợp của tôi và tôi không thể nghĩ ra trường hợp ngoại lệ.

+0

Tôi thích giải pháp của bạn, bẩn thỉu nhưng hoạt động như một sự quyến rũ! –

16

Có thể. Dưới đây là một phương pháp khuyến nông:

public static bool IsOrdered<T>(this IQueryable<T> queryable) 
{ 
    if (queryable == null) 
    { 
     throw new ArgumentNullException("queryable"); 
    } 

    return queryable.Expression.Type == typeof(IOrderedQueryable<T>); 
} 
+0

Cảm ơn, đó là những gì Ive tìm kiếm. Tôi sẽ chỉ thay đổi kiểm tra để thực hiện giao diện thay vì bình đẳng của loại ... typeof (IOrderedQueryable ) .IsAssingableFrom (queryable.Expression.Type) – Ondrej

+0

Lợi ích của thay đổi đó là gì @Ondrej? Tôi cũng nhận thấy rằng không hoạt động nếu OrderBy không phải là hoạt động gần đây nhất :( –

2

Có bạn có thể kiểm tra cây IQueryable.Expression để xem nếu nó gọi bất kỳ OrderBy/ThenBy phương pháp. Cây biểu hiện có thể được kiểm tra bằng cách lấy một lớp từ ExpressionVisitor.

Có một số nội bộ OrderingMethodFinder trong System.Web - mà bạn có thể điều chỉnh. Dưới đây là những gì tôi đã đưa ra:

// Adapted from internal System.Web.Util.OrderingMethodFinder http://referencesource.microsoft.com/#System.Web/Util/OrderingMethodFinder.cs 
class OrderingMethodFinder : ExpressionVisitor 
{ 
    bool _orderingMethodFound = false; 

    protected override Expression VisitMethodCall(MethodCallExpression node) 
    { 
     var name = node.Method.Name; 

     if (node.Method.DeclaringType == typeof(Queryable) && (
      name.StartsWith("OrderBy", StringComparison.Ordinal) || 
      name.StartsWith("ThenBy", StringComparison.Ordinal))) 
     { 
      _orderingMethodFound = true; 
     } 

     return base.VisitMethodCall(node); 
    } 

    public static bool OrderMethodExists(Expression expression) 
    { 
     var visitor = new OrderingMethodFinder(); 
     visitor.Visit(expression); 
     return visitor._orderingMethodFound; 
    } 
} 

Sử dụng nó như vậy:

bool isOrdered = OrderingMethodFinder.OrderMethodExists(myQuery.Expression); 
Các vấn đề liên quan