2010-07-23 72 views
3

我有一個查詢IQueryable並想動態地對其應用排序,排序可以在許多列(asc或desc)上。我已經寫了下面的一般功能:LINQ:在許多列上動態排序

private IQueryable<T> ApplySorting<T,U>(IQueryable<T> query, Expression<Func<T, U>> predicate, SortOrder order) 
    { 
     if (order == SortOrder.Ascending) 
     { 
      { 
       return query.OrderBy<T, U>(predicate); 
      } 
     } 
     else 
     { 
      { 
       return query.OrderByDescending<T, U>(predicate); 
      } 
     } 
    } 

SortOrder的是我的簡單枚舉有兩個值:升序和降序

然後我調用這個函數在一個循環中,該用戶請求的排序每一列。但是我注意到它失敗了,因爲它總是按最後一列使用,而忽略其他列。

後來我發現有上IOrderedQueryable一個「ThenBy」的方法,從而有效的用法是:

var q = db.MyType.OrderBy(x=>x.Col1).ThenBy(y=>y.Col2); //etc. 

但我怎樣才能使它通用?我試圖測試,如果查詢是IOrderedQueryable,但它似乎始終是真實的,即使它是最簡單的var q =從db.MyType x中選擇x

我不知道爲什麼它是這樣設計的。出了什麼問題:

var q = db.MyType.OrderBy(x=>x.Col1).OrderBy(y=>y.Col2); //etc. 

它是這麼多直觀

+0

我認爲他們不會讓.OrderBy(.. Col1中..)。排序依據(.. col2的..)飛是因爲他們知道沒有什麼好辦法,如果預期最終結果是按Col1排序,然後按Col2重新排序整個列表;或Col1,然後是Col2的子排序(按照您的意圖) – 2010-07-23 15:46:52

+0

當您編寫.OrderBy時,查詢執行被延遲,直到您第一次遍歷查詢集時纔會發生任何事情。 – PawelRoman 2010-07-23 15:55:22

回答

0

總猜測,但你可以做這樣的事情?

query.OrderBy(x => 1).ThenBy<T,U>(predicate) 

任何語法錯誤不談,這個想法是做一個排序依據()不影響什麼,然後做實際工作中.ThenBy()方法調用

+0

不錯的黑客,它應該做的工作,但它仍然只是一個黑客。很難相信linq作者沒有想到這種情況。隨着蟒蛇/ Django做這種事情是如此微不足道...... – PawelRoman 2010-07-23 20:04:31

1

你只需要檢查如果查詢已經訂購:

private IQueryable<T> ApplySorting<T,U>(IQueryable<T> query, Expression<Func<T, U>> predicate, SortOrder order) 
{ 
    var ordered = query as IOrderedQueryable<T>; 
    if (order == SortOrder.Ascending) 
    { 
     if (ordered != null) 
      return ordered.ThenBy(predicate); 
     return query.OrderBy(predicate); 
    } 
    else 
    { 
     if (ordered != null) 
      return ordered.ThenByDescending(predicate); 
     return query.OrderByDescending(predicate); 
    } 
} 
+1

這不工作。就像我說的,查詢ALWAYS是IOrderedQueryable類型的事件,如果它是y中最簡單的x選擇x; – PawelRoman 2010-07-23 19:56:42

0

我會寫一個包裝和內部使用linq擴展方法。

var resultList = presentList 
     .MyOrderBy(x => x.Something) 
     .MyOrderBY(y => y.SomethingElse) 
     .MyOrderByDesc(z => z.AnotherThing) 

public IQueryable<T> MyOrderBy(IQueryable<T> prevList, Expression<Func<T, U>> predicate) { 

     return (prevList is IOrderedQueryable<T>) 
      ? query.ThenBy(predicate) 
      : query.OrderBy(predicate); 
} 

public IQueryable<T> MyOrderByDesc(IQueryable<T> prevList, Expression<Func<T, U>> predicate) { 

     return (prevList is IOrderedQueryable<T>) 
      ? query.ThenByDescending(predicate) 
      : query.OrderByDescending(predicate); 
} 

PS:我沒有測試的代碼

+0

如果您測試此代碼,您會發現IQueryable 始終是IOrderedQueryable ,因此總是會調用ThenBy函數,並且OrderBy永遠不會被調用。這與我在寫這篇文章之前試圖實現它的方式類似,並且發現了這個驚喜。 – PawelRoman 2010-07-23 20:00:00

0

擴展到動態的多階:

public static class DynamicExtentions 
{ 
    public static IEnumerable<T> DynamicOrder<T>(this IEnumerable<T> data, string[] orderings) where T : class 
    { 
     var orderedData = data.OrderBy(x => x.GetPropertyDynamic(orderings.First())); 
     foreach (var nextOrder in orderings.Skip(1)) 
     { 
      orderedData = orderedData.ThenBy(x => x.GetPropertyDynamic(nextOrder)); 
     } 
     return orderedData; 
    } 

    public static object GetPropertyDynamic<Tobj>(this Tobj self, string propertyName) where Tobj : class 
    { 
     var param = Expression.Parameter(typeof(Tobj), "value"); 
     var getter = Expression.Property(param, propertyName); 
     var boxer = Expression.TypeAs(getter, typeof(object)); 
     var getPropValue = Expression.Lambda<Func<Tobj, object>>(boxer, param).Compile();    
     return getPropValue(self); 
    } 
} 

例子:

var q =(myItemsToSort.Order(["Col1","Col2"]); 

注:不知道任何IQueryable提供商可以翻譯這個

0

剛剛做出第一個OrderBy靜態,然後總是ThenBy

OrderColumn[] columnsToOrderby = getColumnsToOrderby(); 
IQueryable<T> data = getData(); 

if(!columnToOrderBy.Any()) { } 
else 
{ 
    OrderColumn firstColumn = columnsToOrderBy[0]; 
    IOrderedEnumerable<T> orderedData = 
     firstColumn.Ascending 
     ? data.OrderBy(predicate) 
     : data.OrderByDescending(predicate); 

    for (int i = 1; i < columnsToOrderBy.Length; i++) 
    { 
     OrderColumn column = columnsToOrderBy[i]; 
     orderedData = 
      column.Ascending 
      ? orderedData.ThenBy(predicate) 
      : orderedData.ThenByDescending(predicate); 
    } 
}