使用属性名称排序为字符串

时间:2016-01-20 12:20:53

标签: c# asp.net linq asp.net-core entity-framework-core

我希望我的Web API能够通过字符串参数对其输出进行排序,例如:

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

因为我的API中也有分页支持(skiptake),所以我希望将orderBydescending参数应用于SQL查询直接,以便正确的结果来自数据库。

但是,在执行此操作时,在尝试将orderBy的参数与我希望通过字符串比较排序的类的实际属性进行匹配时,代码可能变得非常难以管理。

我找到了solution,它应该与LINQ to Entities一起使用,因此也可以使用新的EF7,但是当我尝试使用新的Core CLR编译这段代码时,我得到以下消息:< / p>

  

错误CS1503参数2:无法转换为&#39; System.Linq.Expressions.Expression&gt;&#39;到&#39;字符串&#39;

失败的解决方案中的代码是OrderBy<T>方法:

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

似乎新的Core CLR不支持此尝试。有没有其他方法可以使解决方案与新的CLR一起使用?如果不是,我还有什么其他选择来使用EF7进行排序,而不会产生无数ifswitch语句来将输入字符串与属性名称进行比较?

1 个答案:

答案 0 :(得分:8)

您链接的解决方案使用“Expression.Convert”,大部分时间都不能与LINQ to Entities一起使用。

这是一个有效的扩展方法:

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;
}

免责声明:我是GitHub上项目EF+的所有者。

您可以在我的存储库中找到按属性名称排序的其他方法:GitHub

  • OrderByDescending
  • ThenBy
  • ThenByDescending
  • AddOrAppendOrderBy
  • AddOrAppendOrderByDescending

编辑:回答子问题

  

是否可以使用类似的东西对导航属性进行排序   这个,例如属性名称“NavigationProperty.PropertyName”

是的,您可以拆分字符串并循环以使用属性路径创建表达式或使用实际表达式求值程序。

免责声明:我是该项目的所有者Eval-Expressions.NET

该库允许您动态执行所有LINQ方法。

请参阅:LINQ Dynamic

var result = list.OrderByDynamic(x => "NavigationProperty.PropertyName");