'LINQ OrderBy using condition AND Multiple columns
These two work
query.OrderBy(a => a.Name).ThenBy(a => a.LastName)
Also works
query.OrderBy( a=> a.Type == 1 ? a.Name : otherTypeSortOrderColumn)
Similarly you can do
from a in query orderby a.Name,a.LastName select a;
and
From a in query orderby (a.type == 1 ? a.Name : otherTypeSortOrderColumn) select a
How do you mix both?
For each value of Type I want a different column sort, on which there might or might not be more columns that has to have the "ThenBy" sorting applied
Something like
query.OrderBy ( a => a.Type == 1 ? a.Name, A.LastName : a.Type == 2 ? a.Product.Name : ... and so on)
Solution 1:[1]
Maybe you are not aware that you can join linq operations as ever you like
if (thisAndThat)
orderedQuery = query.OrderBy(...);
if (anotherCondition)
orderedQuery = orderedQuery.ThenBy(....);
Solution 2:[2]
If you are working AsEnumerable, consider to create an IComparer for it.
class PropertyComparer<T, TProperty> : IComparer<T>
{
public Func<T, TProperty> PropertySelector {get; set;}
public IComparer<TProperty> PropertyComparer {get; set;} = Comparer<TProperty>.Default;
public Compare(T x, T y)
{
TProperty propertyX = this.PropertySelector(x);
TProperty propertyY = this.PropertySelector(y);
return this.PropertyComparer.Compare(propertyX, propertyY);
}
}
Usage:
var customerComparer = new PropertyComparer<Customer, string>
{
PropertySelector = customer => customer.Name,
PropertyComparer = StringComparer.CurrentCultureIgnoreCase,
}
IEnumerable<Customer> customers = ...
var customersOrderedByName = customers.OrderBy(customer => customer, customerComparer);
There's room for improvement
What if a Customer.Name equals null? Change IComparer.Compare:
public Compare(T x, T y)
{
// TODO: decide if NULL comes first or last
if (x == null)
{
if (y == null)
return 0; // both null
else
return +1; // null comes last
}
else if (y == null)
{
return -1;
}
else
{
// x and y both not null
Solution 3:[3]
I have not found a way to achieve this yet so for now i'm going with a bit more verbose approach to this :
Expression<Func<TEntity, object>> keySelector = x =>
!x.a.HasValue && x.b.HasValue && !x.c.HasValue && !string.IsNullOrEmpty(x.c.LastName) ? x.c.LastName :
!x.a.HasValue && !x.b.HasValue && !x.c.HasValue && x.d.HasValue ? x.d.Name :
!x.a.HasValue && !x.b.HasValue && !x.c.HasValue && !x.d.HasValue && x.e.HasValue ? x.e.Name :
!x.a.HasValue && !x.b.HasValue && !x.c.HasValue && !x.d.HasValue && !x.e.HasValue && x.f.HasValue && !string.IsNullOrEmpty(x.f.Society) ? x.f.Society : string.Empty;
Expression<Func<TEntity, object>> keySelector2 = x =>
!x.a.HasValue && !x.b.HasValue && x.c.HasValue && !string.IsNullOrEmpty(x.c.FirstName) ? x.c.FirstName :
!x.a.HasValue && !x.b.HasValue && !x.c.HasValue && !x.d.HasValue && !x.e.HasValue && x.f.HasValue && !string.IsNullOrEmpty(x.f.LastName) ? x.f.LastName : string.Empty;
Expression<Func<TEntity, object>> keySelector3 = x =>
!x.a.HasValue && !x.b.HasValue && !x.c.HasValue && !x.d.HasValue && !x.e.HasValue && x.f.HasValue && !string.IsNullOrEmpty(x.f.FirstName) ? x.f.FirstName : string.Empty;
query = query.OrderBy(keySelector).ThenBy(keySelector2).ThenBy(keySelector3);
Where TEntity is the type of the class from IQueryable i'm accessing.
If someone has anything better i'm open to suggestions. I thought about implementing an extension using Linq.Extensions to fiddle around with something cleaner but since this is an edge case it would just be hiding more code behind a pretty front.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Klamsi |
| Solution 2 | |
| Solution 3 |
