2010-09-21 3 views
97

Может кто-нибудь объяснить, в чем разница между: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 элементов данных?

ответ

171

Вы должны определенно использовать ThenBy, а не несколько OrderBy звонки. (Я предполагаю, что один из фрагментов в вашем вопросе должен был использовать ThenBy На момент написания этой статьи, два сниппеты идентичны.).

Я хотел бы предложить следующее:

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 к объектам) написать

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

, который был бы эквивалентен

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

как порядок сортировки является стабильным, но вы совершенно не должны:

  • Трудно читать
  • Он не работает хорошо (потому что он переупорядочивает всю последовательность)
  • Возможно, это не Работает в других провайдерах (например, LINQ to SQL)
  • В основном это не так, как OrderBy был предназначен для использования.

Точка OrderBy предназначена для обеспечения «самой важной» проекционной проекции; затем используйте ThenBy (многократно), чтобы указать вторичные, третичные и т.д. заказывающие прогнозы.

эффективен, думать об этом так: OrderBy(...).ThenBy(...).ThenBy(...) позволяет создать единое композиционное сравнение для любых двух объектов, а затем сортировки последовательности раз с помощью этого композитного сравнения. Это почти наверняка то, что вы хотите.

+2

То, что я думал, но почему-то OrderBy, ThenBy, ThenBy, похоже, не сортируется правильно, поэтому я задавался вопросом, правильно ли я использовал его. – DazManCat

+1

+1 для «Это также эквивалентно той части, которую я искал. –

+10

Обратите внимание, что в синтаксисе запроса ключевое слово для заказа - фактически orderby, а не порядок. (_sorry for the pedantry - просто хотел сказать, что однажды исправил сообщение Jon Skeet post_) – fostandy

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

Есть много способов, вы можете использовать это в зависимости от вашего случая использования, но если вы, например, передается список сортировки столбцов и направлений как строки и BOOLS, вы могли бы петлю над ними и использовать их в переключателе, как:

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 отсортирован в нужном порядке, вместо того, чтобы прибегать снова и снова, как другой ответ здесь предостережениями.

+0

Или просто некоторые методы расширения https://stackoverflow.com/a/45486019/1300910 –

0

, если вы хотите, чтобы отсортировать более чем одно поле, то идти на ThenBy:

как этот

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

Да, вы никогда не должны использовать несколько OrderBy, если вы играете с несколькими ключами. ThenBy безопаснее, так как он будет выполнять после OrderBy.

Смежные вопросы