关于c#:在linq查询中设置动态排序名称字段

Setting a dynamic sort name field in a linq query

本问题已经有最佳答案,请猛点这里访问。

我希望能够得到一个使用lambda表达式的OrderBy查询,这样我就可以得到一个使用顶级(n)关键字(大性能提升)的SQL查询。

如果我指定…

1
PaginatedList = query.OrderBy(x => x.QuoteID).Skip(() => skipValue).Take(() => pageSize)

但是,由于我希望orderby字段通过名称的UI选择是动态的,所以我希望这样做:

1
2
3
var propertyInfo = typeof(Data.Quote).GetProperty(sortName);
Expression<Func<Data.Quote, object>> orderField = x => propertyInfo.GetValue(x, null);
PaginatedList = query.OrderBy(orderField).Skip(() => skipValue).Take(() => pageSize)

这给了我一个错误:

"LINQ to Entities does not recognize the method 'System.Object
GetValue(System.Object)' method, and this method cannot be translated
into a store expression."

我试过这个,不是Expression>型的。

1
2
3
var propertyInfo = typeof(Data.Quote).GetProperty(sortName);
Func<Data.Quote, object> orderField = x => propertyInfo.GetValue(x, null);
PaginatedList = query.OrderBy(x => orderField).Skip(() => skipValue).Take(() => pageSize)

我得到这个错误:

"Unable to create a constant value of type [...]. Only primitive types
or enumeration types are supported in this context"

我肯定有办法做到这一点,但目前还不确定如何做到。


以下是如何实现您想要的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
var propertyInfo = typeof(Data.Quote).GetProperty(sortName);

ParameterExpression parameter = Expression.Parameter(typeof(T),"s");
MemberExpression property = Expression.Property(parameter, propertyInfo);
LambdaExpression sort = Expression.Lambda(property, parameter);

MethodCallExpression call = Expression.Call(
                                         typeof(Queryable),
                                        "OrderBy",
                                         new[] {typeof(T), property.Type},
                                         Query.Expression,
                                         Expression.Quote(sort));

var orderedQuery = (IOrderedQueryable<T>)Query.Provider.CreateQuery<T>(call);

PaginatedList = orderedQuery.Skip(skipValue).Take(pageSize);


您需要创建一个表达式来选择该属性,而不是创建表达式。从此源:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static class Utility
{
    //makes expression for specific prop
    public static Expression<Func<TSource, object>> GetExpression<TSource>(string propertyName)
    {
        var param = Expression.Parameter(typeof(TSource),"x");
        Expression conversion = Expression.Convert(Expression.Property
        (param, propertyName), typeof(object));   //important to use the Expression.Convert
        return Expression.Lambda<Func<TSource, object>>(conversion, param);
    }


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

然后您可以按如下所示进行订购:

1
var result=Query.OrderBy(sortName)...;


复制到propertyInfo中的值只是一个对象,因为这是GetProperty()返回的类型。将鼠标悬停在var上方,您将确认这一点。

对象不存在GetValue方法,因此在调用GetValue之前需要将其强制转换为正确的类型。