I have an app that accesses database and has to order results by different fields depending on the input.
Here is my function for sorting:
IQueryable<Entity> GetSortedData(IQueryable<Entity> result, String orderby, bool desc)
{
switch (orderby.ToLower())
{
case "id":
result = result.OrderBy(c => c.Id);
break;
case "code":
result = result.OrderBy(c => c.Code);
break;
case "active":
result = result.OrderBy(c => c.Active);
break;
default:
result = result.OrderBy(c => c.Name);
break;
}
if (pageData.SortDesc)
{
var res = result.ToList();
res.Reverse();
return res.AsQueryable();
}
return result;
}
There are some problems with this code that I don't like:
Too much repetitive code. If it was "pure SQL" query, it would look like
SELECT * FROM data_table
ORDER BY
CASE @OrderBy
WHEN 'id' THEN id
WHEN 'code' THEN code
WHEN 'active' THEN active
ELSE name
END
;
Conversion to list and back for reversing. I can not change return type and I definitely do not want to write even more useless code (essentially doubling switch case with OrderByDescending).
Can anyone suggest ways of making this function better-looking, preferably still using LINQ?
Well, you definitely want to use OrderByDescending instead of reversing. It's not going to be quite as brief as the SQL, but you could at least use:
IQueryable<Entity> GetSortedData(IQueryable<Entity> result, String orderby, bool desc)
{
switch (orderby.ToLowerInvariant())
{
case "id":
return desc ? result.OrderByDescending(c => c.Id) : result.OrderBy(c => c.Id);
case "code":
return desc ? result.OrderByDescending(c => c.Code) : result.OrderBy(c => c.Code);
case "active":
return desc ? result.OrderByDescending(c => c.Active) : result.OrderBy(c => c.Active);
default:
return desc ? result.OrderByDescending(c => c.Name) : result.OrderBy(c => c.Name);
}
}
You could remove that repetition with your own extension method:
public static IOrderedQueryable<TSource> OrderBy<TSource, TKey>(
this IQueryable<TSource> source,
Expression<Func<TSource, TKey>> keySelector,
bool descending) =>
descending ? source.OrderByDescending(keySelector) : source.OrderBy(keySelector);
Then write:
IQueryable<Entity> GetSortedData(IQueryable<Entity> result, String orderby, bool desc)
{
switch (orderby.ToLowerInvariant())
{
case "id": return result.OrderBy(c => c.Id, desc);
case "code": return result.OrderBy(c => c.Code, desc);
case "active": return result.OrderBy(c => c.Active, desc);
default: return result.OrderBy(c => c.Name, desc);
}
}
// this will work with any class
IQueryable<Entity> GetSortedData(
IQueryable<Entity> result, String orderby, bool desc)
{
return result.OrderBy(orderby, desc);
}
// custom order by extension method
// which will work with any class
public static class QueryableHelper
{
public static IQueryable<TModel> OrderBy<TModel>
(this IQueryable<TModel> q, string name, bool desc)
{
Type entityType = typeof(TModel);
PropertyInfo p = entityType.GetProperty(name);
MethodInfo m = typeof(QueryableHelper)
.GetMethod("OrderByProperty")
.MakeGenericMethod(entityType, p.PropertyType);
return(IQueryable<TModel>) m.Invoke(null, new object[] {
q, p , desc });
}
public static IQueryable<TModel> OrderByProperty<TModel, TRet>
(IQueryable<TModel> q, PropertyInfo p, bool desc)
{
ParameterExpression pe = Expression.Parameter(typeof(TModel));
Expression se = Expression.Convert(Expression.Property(pe, p), typeof(object));
var exp = Expression.Lambda<Func<TModel, TRet>>(se, pe);
return desc ? q.OrderByDescending(exp) : q.OrderBy(exp);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With