LINQ to Entities OrderBy 表达式树

Posted

技术标签:

【中文标题】LINQ to Entities OrderBy 表达式树【英文标题】:LINQ to Entities OrderBy Expression Tree 【发布时间】:2016-04-17 18:19:17 【问题描述】:

我正在尝试编写一个 LINQ 查询来 orderBy 由字符串值给出的动态属性。

这是我的原始代码:

 Expression<Func<T, dynamic>> orderBy = i => i.GetType().GetProperty("PropertyName").GetValue(null);

当我尝试运行此 orderBy 时,出现以下异常:

LINQ to Entities 无法识别该方法 'System.Object GetValue(System.Object)' 方法,该方法不能 被翻译成商店表达式。

我试图通过创建一个表达式树来解决这个问题,它会给我相同的结果。代码应该能够根据参数返回任何类型,但我遇到了返回类型的问题。如果我不转换值,我会得到一个不同的错误,说 w Nullable DateTime 不能转换为 Object。这是我到目前为止的代码:

ParameterExpression pe = Expression.Parameter(typeof(T), "s");
Expression<Func<T, dynamic>> orderByExpression = Expression.Lambda<Func<T, dynamic>>(Expression.Convert(Expression.Property(pe, "PropertyName"), typeof(object)), pe);

还有我的新例外:

无法转换类型 'System.Nullable`1[[System.DateTime]]' 输入 '系统.对象'。 LINQ to Entities 仅支持转换 EDM 原语 或枚举类型。

如何编写这个表达式树来返回动态类型?还有我应该在 LINQ 中执行此操作的更好方法吗?

【问题讨论】:

看看get property of inner object 看看Marc Gravells Dynamic OrderBy 【参考方案1】:

Expression&lt;Func&lt;T, TT&gt;&gt; 没有模板参数,它允许您表示引用类型和值类型。当然,您可以构建表达式,但您必须通过反射与它们进行交互。

这将正确地对集合进行排序:

IOrderedEnumerable<TEntityType> SortMeDynamically<TEntityType>(IEnumerable<TEntityType> query, string propertyname)

    var param = Expression.Parameter(typeof(TEntityType), "s");
    var prop = Expression.PropertyOrField(param, propertyname);
    var sortLambda = Expression.Lambda(prop, param);

    Expression<Func<IOrderedEnumerable<TEntityType>>> sortMethod = (() => query.OrderBy<TEntityType, object>(k => null));

    var methodCallExpression = (sortMethod.Body as MethodCallExpression);
    if (methodCallExpression == null)
        throw new Exception("Oops");

    var method = methodCallExpression.Method.GetGenericMethodDefinition();
    var genericSortMethod = method.MakeGenericMethod(typeof(TEntityType), prop.Type);
    var orderedQuery = (IOrderedEnumerable<TEntityType>)genericSortMethod.Invoke(query, new object[]  query, sortLambda.Compile() );

    return orderedQuery;

或者,如果您想在 IQueryable 上使用它(例如,如果您使用的是 EF)

IOrderedQueryable<TEntityType> SortMeDynamically<TEntityType>(IQueryable<TEntityType> query, string propertyname)

    var param = Expression.Parameter(typeof(TEntityType), "s");
    var prop = Expression.PropertyOrField(param, propertyname);
    var sortLambda = Expression.Lambda(prop, param);

    Expression<Func<IOrderedQueryable<TEntityType>>> sortMethod = (() => query.OrderBy<TEntityType, object>(k => null));

    var methodCallExpression = (sortMethod.Body as MethodCallExpression);
    if (methodCallExpression == null)
        throw new Exception("Oops");

    var method = methodCallExpression.Method.GetGenericMethodDefinition();
    var genericSortMethod = method.MakeGenericMethod(typeof(TEntityType), prop.Type);
    var orderedQuery = (IOrderedQueryable<TEntityType>)genericSortMethod.Invoke(query, new object[]  query, sortLambda );

    return orderedQuery;

【讨论】:

以上是关于LINQ to Entities OrderBy 表达式树的主要内容,如果未能解决你的问题,请参考以下文章

分页错误:仅 LINQ to Entities 中的排序输入支持“跳过”方法。方法 'OrderBy' 必须在方法 'Skip' 之前调用

Linq To Entities中的动态排序

在 LINQ to Entities 查询中无法构造实体或复杂类型“Cits.Data.LineImg”。

为啥 LINQ-to-Entities 将此查询放在子选择中?

Linq-to-Entities:带有 WHERE 子句和投影的 LEFT OUTER JOIN

如果存在-UPDATE-else-INSERT 与 Linq-to-Entities?