是否有一种方法可以通过具有不同订购量的IQueryable进行订购

时间:2014-06-05 08:32:17

标签: c# linq entity-framework sql-order-by

例如,我想尝试这样的事情。排序参数可能按不同的顺序排列没有,1个或多个排序列。但我无法使用ThenBy方法,因为它仅在OrderBy之后才可用。下面的代码将继续将订单重置为排序列表中的最后一项。我也不想改变方法签名。非常感谢帮助,谢谢。

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

5 个答案:

答案 0 :(得分:3)

AgentFire的答案实际上是合适的,但在每种情况下对特殊情况都有点啰嗦。我添加了一个扩展方法:

编辑:显然,下面的代码没有正确确定查询是否已经订购;甚至无序版本显然也实现了IOrderedQueryable<T>。使用source.Expression.Type检查IOrderedQueryable<T>显然有效,但我已将此代码留在此处作为更多逻辑方法 - 并且正如此&#34;修复&#34 ;听起来比我更喜欢用我的名字回答:)

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

这样,每个额外的排序选项只会增加很少的代码开销。

答案 1 :(得分: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(如enum SortMode)和List<Sorting>参数:

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

因此,在foreach循环中,您只需要if SortMode并将Item2元组传递给订购者。

答案 2 :(得分: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;
}

答案 3 :(得分:0)

这是我正在使用,试用和测试的代码。基于Jon 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;
}
}

答案 4 :(得分:-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指出我的错误。