LINQ to Entities OrderBy 表达式树

LINQ to Entities OrderBy Expression Tree

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

这是我的原始代码:

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

当我尝试 运行 这个 orderBy 时,我得到了以下异常:

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

我试图通过创建一个表达式树来解决这个问题,它会给我相同的结果。根据参数,代码应该能够 return 任何类型,但我在使用 return 类型时遇到了问题。如果我不转换值,我会得到一个不同的错误,指出 w Nullable DateTime can't be converted to 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);

和我的新例外:

Unable to cast the type 'System.Nullable`1[[System.DateTime]]' to type 'System.Object'. LINQ to Entities only supports casting EDM primitive or enumeration types.

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

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