Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Sorting using property name as string

I would like my Web API to be able to sort its output by a string parameter such as this one:

http://myapi.com/api/people?skip=0&take=50&orderBy=lastName&descending=true.

Because I also have pagination support (with skipand take) in my API, I would like the orderBy and descending parameter to be applied to the SQL query directly, so that the correct result comes from the database.

When doing this however, the code can become very hard to manage when trying to match the parameters for orderBy with the actual properties of the classes I wish to sort by just using string comparisons.

I have found a solution which is supposed to work with LINQ to Entities and thus also with the new EF7, however when I try to compile this code using the new Core CLR, I get the following message:

Error CS1503 Argument 2: cannot convert from 'System.Linq.Expressions.Expression>' to 'string'

The code from the solution that fails is the OrderBy<T>method:

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)
{
    return source.OrderBy(ToLambda<T>(propertyName));
}

It seems like the new Core CLR does not support this attempt. Is there another way to get the solution to work with the new CLR? If no, what other alternatives do I have to enable sorting using EF7 without resulting in countless if or switch statements to compare the input strings to the property names?

like image 229
maxmantz Avatar asked Jan 20 '16 12:01

maxmantz


People also ask

How do you sort properties in C#?

In C#, we can sort the object array by specific property using the following ways: Array. sort() LINQ query.

What is Dynamic Linq?

The Dynamic LINQ library exposes a set of extension methods on IQueryable corresponding to the standard LINQ methods at Queryable, and which accept strings in a special syntax instead of expression trees.


1 Answers

The solution from your link uses an "Expression.Convert" which most of the time doesn't work with LINQ to Entities.

Here is a working extension method:

public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string propertyName)
{
    // LAMBDA: x => x.[PropertyName]
    var parameter = Expression.Parameter(typeof(TSource), "x");
    Expression property = Expression.Property(parameter, propertyName);
    var lambda = Expression.Lambda(property, parameter);

    // REFLECTION: source.OrderBy(x => x.Property)
    var orderByMethod = typeof(Queryable).GetMethods().First(x => x.Name == "OrderBy" && x.GetParameters().Length == 2);
    var orderByGeneric = orderByMethod.MakeGenericMethod(typeof(TSource), property.Type);
    var result = orderByGeneric.Invoke(null, new object[] { source, lambda });

    return (IOrderedQueryable<TSource>)result;
}

Disclaimer: I'm the owner of the project EF+ on GitHub.

You can find other methods to order by property name in my repository: GitHub

  • OrderByDescending
  • ThenBy
  • ThenByDescending
  • AddOrAppendOrderBy
  • AddOrAppendOrderByDescending

EDIT: Answer sub-question

Is it possibly to sort by navigation properties using something like this, e.g. a property name "NavigationProperty.PropertyName"

Yes, you can either split the string and loop to create the expression with the property path or use a real expression evaluator.

Disclaimer: I'm the owner of the project Eval-Expressions.NET

This library allows you to execute all LINQ method dynamically.

See: LINQ Dynamic

var result = list.OrderByDynamic(x => "NavigationProperty.PropertyName");
like image 75
Jonathan Magnan Avatar answered Oct 21 '22 01:10

Jonathan Magnan