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

Posted

技术标签:

【中文标题】使用属性名称作为字符串进行排序【英文标题】:Sorting using property name as string 【发布时间】:2016-01-20 12:20:52 【问题描述】:

我希望我的 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 编译此代码时,我收到以下消息:

错误 CS1503 参数 2:无法从 'System.Linq.Expressions.Expression>' 转换为 'string'

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

public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, string propertyName)

    return source.OrderBy(ToLambda<T>(propertyName));

似乎新的 Core CLR 不支持这种尝试。是否有另一种方法可以使解决方案与新的 CLR 一起使用?如果不是,我必须使用 EF7 启用排序而不导致无数 ifswitch 语句将输入字符串与属性名称进行比较?

【问题讨论】:

为什么不在 Web API 上使用 OData? asp.net/web-api/overview/odata-support-in-aspnet-web-api 哪一行代码给你这个错误?在此处包括失败的 sn-p。 我以前看过 OData。它是否与新的 ASP.NET 5 和 EF7 一起正常工作?是否将排序参数正确映射到 SQL 查询? oData 与 asp.net 5 和 EF7 一起正常工作。 我猜你尝试调用 .OrderBy(ToLambda(propertyName)) 而不是 .OrderBy(propertyName) ,然后因为你使用重载,所以一切都搞砸了。在您的实际列表中尝试执行 myList.OrderBy(propertyName);它可能会给出编译器错误,这意味着您的列表不是 typeof(IQueryable) 那么您知道您必须执行 myList.AsQueryable().OrderBy(propertyName);它与 CLR 无关,只是您混淆了从其他帖子中获取的重载。 【参考方案1】:

链接中的解决方案使用“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

降序排列 然后通过 然后按降序 AddOrAppendOrderBy AddOrAppendOrderByDescending

编辑:回答子问题

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

是的,您可以拆分字符串并循环以使用属性路径创建表达式,也可以使用真正的表达式求值器。

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

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

见:LINQ Dynamic

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

【讨论】:

是否可以使用类似这样的方式按导航属性排序,例如属性名称“NavigationProperty.PropertyName”

以上是关于使用属性名称作为字符串进行排序的主要内容,如果未能解决你的问题,请参考以下文章

C# - 使用属性名称作为字符串由属性排序的代码

从字符串属性名称创建通用表达式

根据字符串属性按字母顺序对对象数组进行排序

按属性名称(字符串值)排序列表? [复制]

iOS - NSFetchRequest:对字符串长度进行排序

根据两个或多个值对通用列表进行排序