LINQ OrderBy versus ThenBy

Quelqu’un peut-il expliquer quelle est la différence entre:

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

et

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

Quelle est la bonne approche si je souhaite commander par 3 éléments de données?

Vous devez absolument utiliser ThenBy plutôt que plusieurs appels OrderBy . (Je suppose que l’un des extraits de votre question était destiné à utiliser ThenBy . Au moment d’écrire ces ThenBy , les deux extraits sont identiques.)

Je suggère ceci:

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

Notez comment vous pouvez utiliser le même nom à chaque fois. Ceci est également équivalent à:

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

Si vous appelez OrderBy plusieurs fois, la séquence sera complètement réorganisée à trois resockets … ainsi, l’appel final sera effectivement dominant. Vous pouvez (dans LINQ to Objects) écrire

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

ce qui serait équivalent à

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

comme l’ordre de sorting est stable, mais vous ne devez absolument pas:

  • C’est difficile à lire
  • Il ne fonctionne pas bien (parce qu’il réordonne toute la séquence)
  • Cela pourrait ne pas fonctionner avec d’autres fournisseurs (par exemple, LINQ to SQL)
  • Il ne s’agit pas de la façon dont OrderBy été conçu pour être utilisé.

Le but de OrderBy est de fournir la projection de commande «la plus importante»; puis utilisez ThenBy (à plusieurs resockets) pour spécifier des projections de ThenBy secondaires, tertiaires, etc.

Effectivement, pensez-y de cette façon: OrderBy(...).ThenBy(...).ThenBy(...) vous permet de construire une comparaison composite unique pour deux objects, puis de sortinger la séquence une fois avec ce composite. Comparaison. C’est presque certainement ce que vous voulez.

J’ai trouvé cette distinction agaçante en essayant de générer des requêtes de manière générique, alors j’ai fait une petite aide pour produire OrderBy / ThenBy dans le bon ordre, pour autant de choses que vous le souhaitez.

 public class EFSortHelper { public static EFSortHelper Create(IQueryable query) { return new EFSortHelper(query); } } public class EFSortHelper : EFSortHelper { protected IQueryable unsorted; protected IOrderedQueryable sorted; public EFSortHelper(IQueryable unsorted) { this.unsorted = unsorted; } public void SortBy(Expression> 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 Sorted { get { return sorted; } } } 

Vous pouvez utiliser cela de nombreuses manières selon votre cas d’utilisation, mais si vous avez par exemple reçu une liste de colonnes et de directions de sorting sous forme de chaînes et de bools, vous pouvez les parcourir et les utiliser dans un commutateur comme:

 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; 

Le résultat dans sortedQuery est sortingé dans l’ordre souhaité, au lieu de recourir encore et encore car l’autre réponse met en garde.

Si vous voulez sortinger plus d’un champ, allez sur ThenBy:

comme ça

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

Oui, vous ne devez jamais utiliser plusieurs commandes si vous jouez avec plusieurs clés. ThenBy est un pari plus sûr car il fonctionnera après OrderBy.