Reputation: 6531
I have an enum which contains a number of different sort orders:
public enum LogSortOrder
{
DateTimeAsc = 1,
DateTimeDesc = 2,
LevelAsc = 3,
LevelDesc = 4,
MessageAsc = 5,
MessageDesc = 6
}
Rather than having to build up my query within a switch statement, I wondered if there was a more efficient or elegant way of achieving this so I don't need to split my query apart and have an ugly switch block like this:
var query = context.Set<Log>().AsQueryable();
switch ( sortOrder )
{
case LogSortOrder.LevelAsc:
query = query.OrderBy( l => l.Level );
break;
case LogSortOrder.LevelDesc:
query = query.OrderByDescending( l => l.Level );
break;
case LogSortOrder.MessageAsc:
query = query.OrderBy( l => l.Message );
break;
case LogSortOrder.MessageDesc:
query = query.OrderByDescending( l => l.Message );
break;
case LogSortOrder.DateTimeAsc:
query = query.OrderBy( l => l.Date );
break;
default:
query = query.OrderByDescending( l => l.Date );
break;
}
return await query
.Skip( offset )
.Take( limit )
.ToListAsync();
Upvotes: 3
Views: 107
Reputation: 832
I think the easiest and the most straight forward way is to keep your logic but wrap it in an extension method so it looks nicer when you use it. This will be easier to maintain too.
public static class SortHelper
{
public static IOrderedQueryable<Log> SortFromCommand(this IQueryable<Log> entities, LogSortOrder sortOrder)
{
IOrderedQueryable<Log> ordered;
switch (sortOrder)
{
case LogSortOrder.LevelAsc:
ordered = entities.OrderBy(l => l.Level);
break;
case LogSortOrder.LevelDesc:
ordered = entities.OrderByDescending( l => l.Level );
break;
case LogSortOrder.MessageAsc:
ordered = entities.OrderBy( l => l.Message );
break;
case LogSortOrder.MessageDesc:
ordered = entities.OrderByDescending( l => l.Message );
break;
case LogSortOrder.DateTimeAsc:
ordered = entities.OrderBy( l => l.Date );
break;
default:
ordered = entities.OrderByDescending( l => l.Date );
break;
}
return ordered;
}
}
Usage:
var sortCommand = LogSortOrder.LevelAsc;
var results = context.Set<Log>().AsQueryable()
.SortFromCommand(sortCommand)
.Skip(10)
.ToList();
Upvotes: 2
Reputation: 17501
You could use a library that can convert strings into linq expressions like so: https://www.nuget.org/packages/System.Linq.Dynamic.Library/
At which point you could (for example) change your enum values to be strings (i.e. DateTimeDesc = "Date desc"
or MessageAsc = "Message"
Then your switch statement would be reduced to:
query = query.OrderBy(sortOrder);
Upvotes: 0
Reputation: 205849
Well, you can build it using System.Linq.Expressions
. I would not call it more efficient or elegant. Probably more flexible (allows easy adding new enum
members), but at the same time more error prone.
var query = context.Set<Log>().AsQueryable();
var sortInfo = sortOrder.ToString();
bool descending = sortInfo.EndsWith("Desc");
var propertyName = sortInfo.Substring(0, sortInfo.Length - (descending ? "Desc" : "Asc").Length);
var parameter = Expression.Parameter(typeof(Log), "log");
var selector = Expression.Lambda(Expression.PropertyOrField(parameter, propertyName), parameter);
query = query.Provider.CreateQuery<Log>(Expression.Call(
typeof(Queryable),
"OrderBy" + (descending ? "Descending" : null),
new [] { parameter.Type, selector.Body.Type},
query.Expression, Expression.Quote(selector)));
// ...
Upvotes: 2