LINQ OrderBy与ThenBy

任何人都可以解释之间的区别是什么:

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项数据进行sorting,哪种方法是正确的?

一定要使用ThenBy而不是多个OrderBy调用。 (我假设你的问题中的一个片段是用ThenBy ,在写这篇文章的时候,这两个片段是相同的。)

我会build议这样的:

 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 ,它将完全重新sorting序列三次…所以最终的调用将是有效的。 你可以 (在LINQ to Objects)编写

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

这将相当于

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

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

  • 这很难阅读
  • 它performance不佳(因为它重新sorting整个序列)
  • 它可能不适用于其他提供者(例如,LINQ to SQL)
  • 这基本上不是OrderBydevise原理。

OrderBy的要点是提供“最重要的”sorting投影; 然后使用ThenBy (重复)来指定二级,三级等sorting投影。

实际上,可以这样想: OrderBy(...).ThenBy(...).ThenBy(...)允许您为任何两个对象构build一个复合比较,然后使用该复合比较。 这几乎可以肯定你想要的。

我发现这个区别在试图以通用的方式构build查询时很烦人,所以我做了一个小小的帮手来按照正确的顺序生成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; } } } 

有很多方法可以使用这取决于你的用例,但是如果你是例如传递一个sorting列和方向的列表作为string和布尔,你可以循环它们,并使用它们在一个开关,如:

 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的结果按照所需的顺序sorting,而不是一遍又一遍,因为这里的其他答案要注意。

如果你想sorting多个字段然后去ThenBy:

喜欢这个

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

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