Sorting using property name as string

倖福魔咒の 提交于 2021-02-18 12:25:08

问题


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?


回答1:


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");


来源:https://stackoverflow.com/questions/34899933/sorting-using-property-name-as-string

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!