Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Best practice to implement a sort property

I have an api Get method which accepts sort property as a string. What is a best solution to handle it without using switch statement?

public ActionResult Index(string sortOrder)
{
   var students = from s in db.Students
                  select s;
   switch (sortOrder)
   {
      case "LastName":
         students = students.OrderByDescending(s => s.LastName);
         break;
      case "EnrollmentDate":
         students = students.OrderBy(s => s.EnrollmentDate);
         break;
      case "Birthday":
         students = students.OrderBy(s => s.Birthday);
         break;
      default:
         students = students.OrderBy(s => s.LastName);
         break;
   }
   return View(students.ToList());
}

Following code I found on microsoft's page, but I believe there is should be more elegant way to do it.

like image 411
mykhailovskyi Avatar asked Feb 10 '26 14:02

mykhailovskyi


1 Answers

Use the following method to achieve flexible sorting. The method requires property name and sorting direction parameters.

public Func<IQueryable<T>, IOrderedQueryable<T>> GetOrderByExpression<T>(string propertyName, bool isDescending = false)
    {
        Type typeQueryable = typeof(IQueryable<T>);
        ParameterExpression argQueryable = System.Linq.Expressions.Expression.Parameter(typeQueryable, "p");
        var outerExpression = System.Linq.Expressions.Expression.Lambda(argQueryable, argQueryable);

        var entityType = typeof(T);
        ParameterExpression arg = System.Linq.Expressions.Expression.Parameter(entityType, "x");

        Expression expression = arg;

        PropertyInfo propertyInfo = entityType.GetProperty(propertyName, BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance);
        expression = System.Linq.Expressions.Expression.Property(expression, propertyInfo);

        LambdaExpression lambda = System.Linq.Expressions.Expression.Lambda(expression, arg);            
        string methodName = isDescending ? "OrderByDescending" : "OrderBy";

        MethodCallExpression resultExp = System.Linq.Expressions.Expression.Call(typeof(Queryable),
                                                                                 methodName,
                                                                                 new Type[] { typeof(T), entityType },
                                                                                 outerExpression.Body,
                                                                                 System.Linq.Expressions.Expression.Quote(lambda));

        var finalLambda = System.Linq.Expressions.Expression.Lambda(resultExp, argQueryable);

        return (Func<IQueryable<T>, IOrderedQueryable<T>>)finalLambda.Compile();
    }

Usage:

IQueryable<Student> query = db.Set<Student>();
var orderBy = GetOrderByExpression<Student>(sortOrder, true);

if(orderBy != null){
   query = orderBy(query);
}
like image 52
Yared Avatar answered Feb 15 '26 14:02

Yared