在linq查询中设置动态排序名称字段

时间:2016-11-15 15:09:14

标签: c# .net entity-framework linq linq-to-sql

我希望能够使用lambda表达式获得OrderBy查询,以便获得带有TOP(n)关键字的SQL查询(提高性能)。

如果我指定......我能做到这一点。

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

但是因为我希望orderBy字段通过UI选择名称来动态,我想做这样的事情:

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无法识别方法'System.Object   GetValue(System.Object)'方法,此方法无法翻译   进入商店表达。“

我尝试过这种类型Expression<Func<T, object>>

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)

我收到了这个错误:

  

“无法创建[...]类型的常量值。只有基本类型   或者在此上下文中支持枚举类型“

我确信有办法实现这一目标,但目前还不确定如何。

3 个答案:

答案 0 :(得分:3)

以下是如何实现您的目标:

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)

而不是你需要创建一个表达式来选择那个属性。从这个source

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

然后您可以按照我在下面显示的顺序订购:

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

答案 2 :(得分:1)

复制到propertyInfo的值只是一个Object,因为它是GetProperty()返回的类型。将鼠标悬停在var上即可确认。

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