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 données?
Vous devriez définitivement utiliser ThenBy
plutôt que plusieurs appels OrderBy
. (Je suppose que l'un des extraits de votre question était censé utiliser ThenBy
. Au moment de la rédaction de cet article, les deux extraits sont identiques.)
Je suggérerais 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. Cela équivaut également à:
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 réorganisée complètement trois fois ..., de sorte que le dernier appel sera effectivement dominant. Vous pouvez (dans LINQ to Objects) écrire
foo.OrderBy(x).OrderBy(y).OrderBy(z)
ce qui équivaudrait à
foo.OrderBy(z).ThenBy(y).ThenBy(x)
l'ordre de tri est stable, mais vous ne devez absolument pas:
OrderBy
a été conçu pour être utilisé.Le but de OrderBy
est de fournir la "plus importante" projection de classement; utilisez ensuite ThenBy
(à plusieurs reprises) pour spécifier des projections de commandes secondaires, tertiaires, etc.
Effectivement, réfléchissez-y de la manière suivante: OrderBy(...).ThenBy(...).ThenBy(...)
vous permet de créer une comparaison composite unique pour deux objets quelconques, puis de trier la séquence une fois en utilisant cette comparaison composite. C'est presque certainement ce que vous voulez.
J'ai trouvé cette distinction agaçante en essayant de créer des requêtes de manière générique. J'ai donc créé une petite aide pour produire OrderBy/ThenBy dans le bon ordre, pour autant de sortes que vous le souhaitez.
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;
}
}
}
Cela peut être utilisé de différentes manières en fonction de votre cas d'utilisation, mais si, par exemple, vous passez une liste de colonnes de tri et d'indications sous forme de chaînes et d'objets booléens, vous pouvez les parcourir et les utiliser comme suit:
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 trié dans l'ordre souhaité, au lieu d'être utilisé encore et encore comme le dit l'autre réponse ici.
si vous voulez trier plus d'un champ, optez pour ThenBy:
comme ça
list.OrderBy(personLast => person.LastName)
.ThenBy(personFirst => person.FirstName)
Oui, vous ne devriez jamais utiliser plusieurs OrderBy si vous jouez avec plusieurs clés . ThenBy est un pari plus sûr puisqu'il sera performant après OrderBy.