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

Posted

技术标签:

【中文标题】在 linq 查询中设置动态排序名称字段【英文标题】:Setting a dynamic sort name field in a linq query [duplicate] 【发布时间】:2016-11-15 15:09:13 【问题描述】:

我希望能够使用 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&lt;Func&lt;T, object&gt;&gt;的类型

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)

我得到这个错误:

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

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

【问题讨论】:

感谢所有建议,我找到的最佳解决方案是:***.com/questions/41244/… 必须感谢那些发现重复问题的人,这正是我所需要的,非常感谢!找这个很久了 【参考方案1】:

这里是如何实现你想要的:

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

【讨论】:

这也适用于单向排序,但source.Expression 必须是Query.Expression 真正的短手解决方案 注意命名约定在我上面的代码中应该是小写的query,因为它是一个变量 固定变量名。 Query 是变量在 OP 上的命名方式。【参考方案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)...;

【讨论】:

【参考方案3】:

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

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

【讨论】:

以上是关于在 linq 查询中设置动态排序名称字段的主要内容,如果未能解决你的问题,请参考以下文章

如何在 linq 查询中设置内连接

在 Linq to SQL 查询中设置非列属性值

根据需要在LINQ查询分配对象中设置日期格式

根据来自另一个模型的异步查询在模型中设置虚拟字段

可以在实体框架中设置列排序

SQL中查询多个字段时,GROUP BY 要怎么使用?