codeproject - LINQ OrderBy versus ThenBy
code project español (4)
Encontré esta distinción molesta al tratar de crear consultas de manera genérica, así que hice un pequeño ayudante para producir OrderBy / ThenBy en el orden correcto, para tantos géneros como desee.
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;
}
}
}
Hay muchas maneras en que puede usar esto dependiendo de su caso de uso, pero si por ejemplo pasara una lista de columnas de orden y direcciones como cadenas y bools, podría recorrerlas y usarlas en un interruptor como:
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;
El resultado en sortedQuery
está ordenado en el orden deseado, en lugar de recurrir una y otra vez, como advierte la otra respuesta aquí.
¿Alguien puede explicar cuál es la diferencia entre:
tmp = invoices.InvoiceCollection
.OrderBy(sort1 => sort1.InvoiceOwner.LastName)
.OrderBy(sort2 => sort2.InvoiceOwner.FirstName)
.OrderBy(sort3 => sort3.InvoiceID);
y
tmp = invoices.InvoiceCollection
.OrderBy(sort1 => sort1.InvoiceOwner.LastName)
.ThenBy(sort2 => sort2.InvoiceOwner.FirstName)
.ThenBy(sort3 => sort3.InvoiceID);
¿Cuál es el enfoque correcto si deseo ordenar por 3 elementos de datos?
Sí, nunca debes usar OrderBy múltiple si juegas con varias teclas. Entonces, es una apuesta más segura ya que funcionará después de OrderBy.
si quieres ordenar más de un campo, entonces elige ThenBy:
Me gusta esto
list.OrderBy(personLast => person.LastName)
.ThenBy(personFirst => person.FirstName)
Definitivamente debe usar ThenBy
lugar de múltiples llamadas OrderBy
. (Supongo que uno de los fragmentos en su pregunta estaba destinado a usar ThenBy
. En el momento de escribir estas ThenBy
, los dos fragmentos son idénticos).
Sugeriría esto:
tmp = invoices.InvoiceCollection
.OrderBy(o => o.InvoiceOwner.LastName)
.ThenBy(o => o.InvoiceOwner.FirstName)
.ThenBy(o => o.InvoiceID);
Tenga en cuenta cómo puede usar el mismo nombre cada vez. Esto también es equivalente a:
tmp = from o in invoices.InvoiceCollection
orderby o.InvoiceOwner.LastName,
o.InvoiceOwner.FirstName,
o.InvoiceID
select o;
Si llama a OrderBy
varias veces, reordenará la secuencia por completo tres veces ... para que la llamada final sea la dominante. Puedes (en LINQ to Objects) escribir
foo.OrderBy(x).OrderBy(y).OrderBy(z)
que sería equivalente a
foo.OrderBy(z).ThenBy(y).ThenBy(x)
como el orden de clasificación es estable, pero no debes:
- Es difícil de leer
- No funciona bien (porque reordena toda la secuencia)
- Es posible que no funcione en otros proveedores (por ejemplo, LINQ a SQL)
- Básicamente no es cómo
OrderBy
fue diseñado para ser utilizado.
El objetivo de OrderBy
es proporcionar la proyección de pedido "más importante"; luego use ThenBy
(repetidamente) para especificar proyecciones de ordenamiento secundarias, terciarias, etc.
Efectivamente, OrderBy(...).ThenBy(...).ThenBy(...)
esta manera: OrderBy(...).ThenBy(...).ThenBy(...)
permite construir una única comparación compuesta para dos objetos, y luego ordenar la secuencia una vez usando ese compuesto comparación. Eso es casi seguro lo que quieres.