2014-06-05 55 views
2

例如,我想尝试这样的事情。排序参数可能不包含任何顺序,也可能有一个或多个排序列。但我不能使用ThenBy方法,因为它只能在OrderBy之后才可用。下面的代码将继续重置排序列表中最后一项的顺序。我不想改变方法签名。帮助将不胜感激,谢谢。有没有办法通过IQueryable订购不同数量的订单

public IQueryable<Person> FilterList(string forename, List<Sorting> sorting) 
{ 
    IQueryable<Person> query = dc.Set<Person>(); 

    if(!string.IsNullOrEmpty(forename)){ 
     query = query.Where(w=>w.Forename.Contains(forename)); 

    foreach(var sort in sorting) 
    { 
     switch(sort.By) 
     { 
      case "asc": 
       switch(sort.Sort) 
       { 
        case "forename": 
         query = query.OrderBy(o=>o.Forename); 
         break; 

        case "surname": 
         query = query.OrderBy(o=>o.Surname); 
         break; 
       } 
       break; 

      case "desc": 
       switch(sort.Sort) 
       { 
        case "forename": 
         query = query.OrderByDescending(o=>o.Forename); 
         break; 

        case "surname": 
         query = query.OrderByDescending(o=>o.Surname); 
         break; 
       } 
       break; 
     } 
    } 

    return query; 
} 

public class Sorting 
{ 
    public string Sort{get;set;} 
    public string By{get;set;} 
} 
+0

这是一件好事,看看这个:http://stackoverflow.com/questions/41244/dynamic-linq-orderby-on-ienumerablet当你想动态订购(即使它不会直接解决你的问题) –

+0

你也可以看看:[按匿名类型字段排序](http://stackoverflow.com/questions/22429156/order-by-字段在一个匿名类型) – nlips

回答

1

您可能需要使用转换:

var sortedQueryable = query as IOrderedQueryable<Person>; 

if (sortedQueryable != null) 
{ 
    query = sortedQueryable.ThenBy(o => o.Forename); 
} 
else 
{ 
    query = query.OrderBy(o => o.Forename); 
} 

在每次迭代它会做。


而且,我会改变魔术字符串 “ASC” 和 “DESC”,以枚举(如enum SortMode),并List<Sorting>参数如下:

List<Tuple<Expression<Func<Person, object>>, SortMode>> parameter; 

因此,在您foreach循环中,您只需要到ifSortMode并将元组的Item2传递给订阅者。

+0

我实际上使用枚举,但为了方便我的例子是在字符串。不过,我很高兴你提到它,很高兴按照别人的方式了解你的编码。 –

+0

AgentFire为此欢呼。你的回答与我给出的例子一致。我必须把乔恩的答案作为标记,因为这是我可以重复使用的东西。再次感谢。 +1 –

0

第一次订购一个常量,所以你有一个IOrderedQueryable<T>,那么你可以通过ThenBy方法做所有的定制订购。

public IQueryable<Person> FilterList(string forename, List<Sorting> sorting) { 
    IQueryable<Person> query = dc.Set<Person>(); 
    if(!string.IsNullOrEmpty(forename)){ 
     query = query.Where(w=>w.Forename.Contains(forename)); 

    var orderedQuery = query.OrderBy(x => 1); 

    foreach(var sort in sorting) { 
     switch(sort.By) { 
      case "asc": 
       switch(sort.Sort) { 
        case "forename": 
         orderedQuery = orderedQuery.ThenBy(o=>o.Forename); 
        break; 
        case "surname": 
         orderedQuery = orderedQuery.ThenBy(o=>o.Surname); 
        break; 
       } 
      break; 
      case "desc": 
       switch(sort.Sort) { 
        case "forename": 
         orderedQuery = orderedQuery.ThenByDescending(o=>o.Forename); 
        break; 
        case "surname": 
         orderedQuery = orderedQuery.ThenByDescending(o=>o.Surname); 
        break; 
       } 
      break; 
     } 
    } 

    return orderedQuery; 
} 
+0

不必要的顺序“1”? – AgentFire

+0

为什么不必要?你读过我的解释吗? – Maarten

+0

是的,这仍然可能会生成SQL代码,以单个数字排序。 – AgentFire

3

AgentFire的答案是非常合适的,但在每种情况下都有一点冗长的特殊情况。我会添加一个扩展方法:

编辑:显然,下面的代码不能正确确定查询是否已经命令;即使是无序版本也实现了IOrderedQueryable<T>,显然。使用source.Expression.Type检查IOrderedQueryable<T>显然的作品,但我已经把这个代码留在这里作为更多逻辑的方法 - 并且因为这个“修复”听起来比我想要的答案更脆弱:)

public static IOrderedQueryable<T> AddOrdering<T, TKey>(
    this IQueryable<T> source, 
    Expression<Func<T, TKey>> keySelector, 
    bool descending) 
{ 
    IOrderedQueryable<T> ordered = source as IOrderedQueryable<T>; 
    // If it's not ordered yet, use OrderBy/OrderByDescending. 
    if (ordered == null) 
    { 
     return descending ? source.OrderByDescending(keySelector) 
          : source.OrderBy(keySelector); 
    } 
    // Already ordered, so use ThenBy/ThenByDescending 
    return descending ? ordered.ThenByDescending(keySelector) 
         : ordered.ThenBy(keySelector); 
} 

然后调用代码变为:

foreach(var sort in sorting) 
{ 
    bool descending = sort.By == "desc"; 
    switch (sort.Sort) 
    { 
     case "forename": 
      query = query.AddOrdering(o => o.Forename, descending); 
      break; 
     case "surname": 
      query = query.AddOrdering(o => o.Surname, descending); 
      break; 
    } 
} 

这样,每增加一个排序选项只增加了一个小小的代码开销。

+0

当我至少需要两个地方的algorythm时,我会选择写一个扩展名。 – AgentFire

+0

@AgentFire:在相同的方法中,使用它的代码已经*在两个不同的地方调用它。我不清楚使用'Expression >'是否总是合适 - 它取决于提供者翻译是否使用类型参数来确定如何处理它。 –

+0

嗨乔恩,代码不适合我。在扩展方法内部,有序变量永远不会为空,因此总是调用ThenBy。有什么想法吗? :-D –

-1

有很多选项可以做到这一点。例如:

bool isSorted = false; 

foreach(var sort in sorting) 
{ 
    switch(sort.By) 
    { 
     case "asc": 

      switch(sort.Sort) 
      { 
       case "forename": 
        if (!isSorted) 
        { 
         query = query .OrderBy(o => o.Forename); 
         isSorted = true; 
        } 
        else 
        { 
         query = ((IOrderedQueryable<Person>)query).ThenBy(o => o.Forename); 
        } 
       ... 
      } 
     break; 
     case "desc": 
       ... 
    } 
} 

编辑

感谢AgentFire指出我的错误。

+4

'ThenBy'将不会编译,因为它不存在于'IQueryable '中。 – AgentFire

0

这是我正在使用,试用和测试的代码。基于乔恩Skeets解决方案,信贷给他,我只是为我的目的调整。

public static IOrderedQueryable<T> AddOrdering<T, TKey>(
this IQueryable<T> source, 
Expression<Func<T, TKey>> keySelector, 
bool descending) 
{ 

// If it's not ordered yet, use OrderBy/OrderByDescending. 
if(source.Expression.Type != typeof(IOrderedQueryable<T>)) 
{ 
    return descending ? source.OrderByDescending(keySelector) 
         : source.OrderBy(keySelector); 
} 
// Already ordered, so use ThenBy/ThenByDescending 
return descending ? ((IOrderedQueryable<T>)source).ThenByDescending(keySelector) 
        : ((IOrderedQueryable<T>)source).ThenBy(keySelector); 
} 

然后调用代码变为:

foreach(var sort in sorting) 
{ 
bool descending = sort.By == "desc"; 
switch (sort.Sort) 
{ 
    case "forename": 
     query = query.AddOrdering(o => o.Forename, descending); 
     break; 
    case "surname": 
     query = query.AddOrdering(o => o.Surname, descending); 
     break; 
} 
} 
相关问题