LINQ to Entities OrderBy表达式树

时间:2016-01-12 23:03:14

标签: c# linq linq-to-entities entity-framework-6 expression-trees

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

以下是我的原始代码:

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

当我尝试运行此命令时,我遇到以下异常:

  

LINQ to Entities无法识别该方法   &#39; System.Object GetValue(System.Object)&#39;方法,这种方法不能   被翻译成商店表达。

我正在尝试通过创建一个能够给我相同结果的表达式树来解决这个问题。代码应该能够返回任何类型,具体取决于参数,但我遇到了返回类型的问题。如果我没有转换该值,我会得到一个不同的错误,即可以将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);

和我的新例外:

  

无法转换类型   &#39; System.Nullable`1 [[System.DateTime的]&#39;输入   &#39; System.Object的&#39 ;. LINQ to Entities仅支持转换EDM原语   或枚举类型。

如何编写此表达式树以返回动态类型?还有一种更好的方法我应该在LINQ中这样做吗?

1 个答案:

答案 0 :(得分:4)

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

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

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