使用字段名称作为字符串调用OrderBy()

The*_*dge 6 c# linq entity-framework

我使用的是.NET 4.51,EF 6

我对我的存储库层进行了多次调用,我需要在升级或降序的单个字段上执行一些基本排序,例如:

在此输入图像描述

结果GetAllList()是一个List<T>.现在不幸的是,Id我必须排序的字段并不总是被调用,Id也不是Text字段.它们可以是其他东西,例如MyId,SomeTextField等等.

所以我想知道是否有一种方法可以通过为字段名称提供字符串来执行OrderBy()OrderByDescending()子句:

_Repository.GetAllList().OrderBy(r => r."SomeTextField")
Run Code Online (Sandbox Code Playgroud)

通过这种方式,我可以将所有这些代码移动到一个通用方法.

任何指针都非常感激.

Rob*_*Rob 13

这将有效:

public static class LinqExtensions 
{
    private static PropertyInfo GetPropertyInfo(Type objType, string name)
    {
        var properties = objType.GetProperties();
        var matchedProperty = properties.FirstOrDefault (p => p.Name == name);
        if (matchedProperty == null)
            throw new ArgumentException("name");

        return matchedProperty;
    }
    private static LambdaExpression GetOrderExpression(Type objType, PropertyInfo pi)
    {
        var paramExpr = Expression.Parameter(objType);
        var propAccess = Expression.PropertyOrField(paramExpr, pi.Name);
        var expr = Expression.Lambda(propAccess, paramExpr);
        return expr;
    }

    public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> query, string name)
    {
        var propInfo = GetPropertyInfo(typeof(T), name);
        var expr = GetOrderExpression(typeof(T), propInfo);

        var method = typeof(Enumerable).GetMethods().FirstOrDefault(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
        var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);     
        return (IEnumerable<T>) genericMethod.Invoke(null, new object[] { query, expr.Compile() });
    }

    public static IQueryable<T> OrderBy<T>(this IQueryable<T> query, string name)
    {
        var propInfo = GetPropertyInfo(typeof(T), name);
        var expr = GetOrderExpression(typeof(T), propInfo);

        var method = typeof(Queryable).GetMethods().FirstOrDefault(m => m.Name == "OrderBy" && m.GetParameters().Length == 2);
        var genericMethod = method.MakeGenericMethod(typeof(T), propInfo.PropertyType);     
        return (IQueryable<T>) genericMethod.Invoke(null, new object[] { query, expr });
    }
}
Run Code Online (Sandbox Code Playgroud)

测试:

var r = new List<temp> { 
    new temp { a = 5 }, 
    new temp { a = 1 }, 
    new temp { a = 15 }
}.OrderBy("a");
Run Code Online (Sandbox Code Playgroud)

给出正确的结果(1,5,15) - 并为EF使用提供延迟执行

如果需要,您将需要实现重载.


nma*_*ait 6

它必须是一个字符串吗?为什么不只是创建一个将Func键选择器作为参数的方法.

public List<T> GetAllListOrdered<T,TProp>(SimpleOrderingDirectionEnum direction, Func<T,TProp> keySelector)
{
    return direction == SimpleOrderingDirectionEnum.Ascending ? _Repository.GetAllList().OrderBy(keySelector).ToList() : _Repository.GetAllList().OrderByDescending(keySelector).ToList();
}
Run Code Online (Sandbox Code Playgroud)

然后把它称为

Func<ObjectToSortType, ObjectPropertyToSortBy> keySelector = r => r.Id;
GetAllListOrdered(SimpleOrderingDirectionEnum.Ascending, keySelector);
Run Code Online (Sandbox Code Playgroud)

  • 如果我们使用 linq toEntity,这不会转换为 sql order by,因为 linqtoentities 需要表达式树。请改用“Expression&lt;Func&lt;T,TProp&gt;&gt;”。 (2认同)

The*_*dge 3

谢谢大家。罗布,你的解决方案与我最终得到的非常接近。

根据您的见解,我做了更多搜索,并在IEnumerable<T> 上的 Dynamic LINQ OrderBy(第二篇文章)中找到了 Marc Gravel 的答案。

它添加了动态作为额外的奖励。