【问题标题】:LINQ OrderBy versus ThenByLINQ OrderBy 和 ThenBy
【发布时间】:2020-06-10 17:07:41
【问题描述】:

谁能解释两者之间的区别:

tmp = invoices.InvoiceCollection
              .OrderBy(sort1 => sort1.InvoiceOwner.LastName)
              .OrderBy(sort2 => sort2.InvoiceOwner.FirstName)
              .OrderBy(sort3 => sort3.InvoiceID);

tmp = invoices.InvoiceCollection
              .OrderBy(sort1 => sort1.InvoiceOwner.LastName)
              .ThenBy(sort2 => sort2.InvoiceOwner.FirstName)
              .ThenBy(sort3 => sort3.InvoiceID);

如果我想按 3 项数据排序,哪种方法是正确的?

【问题讨论】:

    标签: linq


    【解决方案1】:

    你应该绝对使用ThenBy而不是多个OrderBy调用。

    我建议这样做:

    tmp = invoices.InvoiceCollection
                  .OrderBy(o => o.InvoiceOwner.LastName)
                  .ThenBy(o => o.InvoiceOwner.FirstName)
                  .ThenBy(o => o.InvoiceID);
    

    请注意如何每次都使用相同的名称。这也相当于:

    tmp = from o in invoices.InvoiceCollection
          orderby o.InvoiceOwner.LastName,
                  o.InvoiceOwner.FirstName,
                  o.InvoiceID
          select o;
    

    如果您多次调用OrderBy,它将有效地重新排序序列完全三次......因此最终调用将有效地成为主要调用。你可以(在 LINQ to Objects 中)写

    foo.OrderBy(x).OrderBy(y).OrderBy(z)
    

    相当于

    foo.OrderBy(z).ThenBy(y).ThenBy(x)
    

    因为排序顺序是稳定的,但你绝对不应该:

    • 很难阅读
    • 表现不佳(因为它会重新排序整个序列)
    • 它可能在其他提供程序(例如 LINQ to SQL)中工作
    • 这基本上不是 OrderBy 的设计用途。

    OrderBy的重点是提供“最重要”的排序投影;然后使用ThenBy(重复)指定二级、三级等排序预测。

    实际上,这样想:OrderBy(...).ThenBy(...).ThenBy(...) 允许您为任意两个对象构建单个复合比较,然后使用该复合比较对序列一次进行排序。这几乎肯定是你想要的。

    【讨论】:

    • 这就是我的想法,但由于某种原因,OrderBy,ThenBy,ThenBy 似乎没有正确排序,所以我想知道我是否正确使用它。
    • 请注意,在查询语法中,用于排序的关键字实际上是 orderby,而不是 order by。 (对迂腐感到抱歉 - 只是想说我曾经纠正过 Jon Skeet 的一篇帖子
    • 乔恩,在 但你绝对不应该 部分对我来说有些东西不适合(这与使用 linq 流利的语法应用多个 order bys 相关,因为它转换为 ThenBy ,在本地查询中):它表现不佳(因为它重新排序了整个序列) - 你的意思是 2nd 或 3rd order by reorders 整个序列?如果是这样,在重新排序序列丢弃之前的排序后,它如何仍转换为 ThenBy ?
    • @Veverke:它重新排序整个序列,但以一种稳定的方式,所以如果两个值具有相同的 z 值,排序将取决于 y 然后取决于 x。
    • @Veverke:OrderBy(a).OrderBy(b).OrderBy(c) 仍然使用前面排序的输出,并重新排序整个事物,但它保留了现有顺序(来自前面的步骤),其中两个元素在新比较下相等.想象一下,我们只有OrderBy(a).OrderBy(b)OrderBy(a) 的结果以a 递增顺序,然后根据b 重新排序。在最终结果中,如果两个值具有相同的b 值,则由于排序稳定,它们将按a 排序 - 所以它等效于OrderBy(b).ThenBy(a)
    【解决方案2】:

    在尝试以通用方式构建查询时,我发现这种区别很烦人,所以我做了一个小帮手,以正确的顺序生成 OrderBy/ThenBy,您可以根据需要进行多种排序。

    public class EFSortHelper
    {
      public static EFSortHelper<TModel> Create<TModel>(IQueryable<T> query)
      {
        return new EFSortHelper<TModel>(query);
      }
    }  
    
    public class EFSortHelper<TModel> : EFSortHelper
    {
      protected IQueryable<TModel> unsorted;
      protected IOrderedQueryable<TModel> sorted;
    
      public EFSortHelper(IQueryable<TModel> unsorted)
      {
        this.unsorted = unsorted;
      }
    
      public void SortBy<TCol>(Expression<Func<TModel, TCol>> sort, bool isDesc = false)
      {
        if (sorted == null)
        {
          sorted = isDesc ? unsorted.OrderByDescending(sort) : unsorted.OrderBy(sort);
          unsorted = null;
        }
        else
        {
          sorted = isDesc ? sorted.ThenByDescending(sort) : sorted.ThenBy(sort)
        }
      }
    
      public IOrderedQueryable<TModel> Sorted
      {
        get
        {
          return sorted;
        }
      }
    }
    

    根据您的用例,您可以通过多种方式使用它,但例如,如果您将排序列和方向列表作为字符串和布尔值传递,您可以遍历它们并在开关中使用它们,例如:

    var query = db.People.AsNoTracking();
    var sortHelper = EFSortHelper.Create(query);
    foreach(var sort in sorts)
    {
      switch(sort.ColumnName)
      {
        case "Id":
          sortHelper.SortBy(p => p.Id, sort.IsDesc);
          break;
        case "Name":
          sortHelper.SortBy(p => p.Name, sort.IsDesc);
          break;
          // etc
      }
    }
    
    var sortedQuery = sortHelper.Sorted;
    

    sortedQuery 中的结果按所需顺序排序,而不是像此处的其他答案所警告的那样一遍又一遍地使用。

    【讨论】:

    【解决方案3】:

    如果您想对多个字段进行排序,请选择 ThenBy:

    喜欢这个

    list.OrderBy(personLast => person.LastName)
                .ThenBy(personFirst => person.FirstName)
    

    【讨论】:

      【解决方案4】:

      是的,如果您使用多个键,则永远不应该使用多个 OrderBy。 ThenBy 是更安全的选择,因为它将在 OrderBy 之后执行。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-03-04
        • 2018-09-16
        • 1970-01-01
        • 2021-04-17
        相关资源
        最近更新 更多