【问题标题】:Use a List of sort expression to sort a queryable使用排序表达式列表对可查询对象进行排序
【发布时间】:2016-06-25 10:40:23
【问题描述】:

我正在构建一个存储库,并希望能够将排序列表传递给一个函数,以便以正确的顺序接收实体并可能分页。

我发现,如果您使用反向排序列表并对每个排序表达式使用 Orderby,则 linq 将正确排序。

        foreach (var s in sorts.Reverse())
        {
            query = query.OrderBy(s);
        }

但是,在测试添加排序方向时,我发现它只采用第一个排序方向,并且似乎将该方向应用于每个排序。

    private void applySorts(ref IQueryable<TEntity> query, Dictionary<Expression<Func<TEntity, dynamic>>, string> sorts)
    {
        if (sorts != null)
        {
            foreach (var s in sorts.Reverse())
            {
                Expression<Func<TEntity, dynamic>> expr = s.Key;
                string dir = s.Value;
                if (dir == "d")
                {
                    query = query.OrderByDescending(expr);
                }
                else
                {
                    query = query.OrderBy(expr);
                }
            }
        }
    }

我最初尝试在第一次排序时使用 OrderBy,然后切换到 ThenBy,但这不可能,因为 ThenBy 需要 IOrderedQueryable 类型。

我想注意使用字典可能不是最好的,如果您有更好的想法,请分享。但是,我只是想让它运行起来,看看情况如何。

我正在使用 C#、Linq 和实体框架。

提前感谢您的宝贵时间。

更新:不幸的是,我发现这不支持数字排序。错误(无法将类型“System.Int32”转换为类型“System.Object”。)

【问题讨论】:

标签: c# linq sorting repository-pattern


【解决方案1】:

从语法上讲,您只需要一个 IOrderedQueryable 类型的临时变量。

我会尝试类似:

    private void applySorts(ref IQueryable<TEntity> query, Dictionary<Expression<Func<TEntity, dynamic>>, string> sorts)
{
    if (sorts != null)
    {
        IOrderedQueryable<TEntity> tempQuery = null;
        bool isFirst = true;
        foreach (var s in sorts.Reverse())
        {
            Expression<Func<TEntity, dynamic>> expr = s.Key;
            string dir = s.Value;
            if (first) 
            {
                first = false;
                if (dir == "d")
                {
                    tempQuery = query.OrderByDescending(expr);
                }
                else
                {
                    tempQuery = query.OrderBy(expr);
                }
            }
            else 
            {   
                if (dir == "d")
                {
                    tempQuery = tempQuery.ThenByDescending(expr);
                }
                else
                {
                    tempQuery = tempQuery.ThenBy(expr);
                }
            }
        }
        query = tempQuery;
    }
}

编辑:

上述解决方案的关键是 IOrderedQueryable 是 IQueryable。

我自己没试过。但是,我要强调的是,这只是一个语法解决方案。

【讨论】:

    【解决方案2】:

    您可以使用ThenBy() 方法链接您的过滤器,如下所示:

    bool first = true;
    
    foreach(var s in sorts) 
    {
        query = first ? query.OrderBy(s) : query.ThenBy(s);
    }
    // It will became like query.OrderBy(a => a.A).ThenBy(a => a.B).ThenBy(a => a.C)...
    

    如果您知道要排序的属性,还可以在 LINQ 查询中使用多列排序:

    var result = (from row in list
                  orderby row.A, row.B, row.C
                  select row).ToList();
    

    【讨论】:

    • var query = query.OrderBy(sorts[0]); 不会编译。
    • @hvd 好吧,我没注意到这是一本字典。 :) 然后他可以像他那样将循环更改为foreach 而不是for。只需将OrderBy() 应用于第一个排序表达式,将ThenBy() 应用于所有其他表达式。
    • 嘿,我的意思是你不能有一个与参数同名的局部变量,但是,是的,也是。 :) 使用您编辑的版本,query.ThenBy 将无法编译,query 的类型为 IQueryable&lt;T&gt;。你更接近你的第一个版本,你确实需要一个单独的变量,你只需要给它一个不同的名字。
    猜你喜欢
    • 2010-10-16
    • 2014-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多