LINQ到实体通过表达式树排序

Set*_*urg 4 c# linq linq-to-entities expression-trees entity-framework-6

我正在尝试编写LINQ查询以通过字符串值给定的动态属性来orderB。

这是我的原始代码:

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

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

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);
Run Code Online (Sandbox Code Playgroud)

和我的新例外:

无法将类型'System.Nullable`1 [[System.DateTime]]'强制转换为类型'System.Object'。LINQ to Entities仅支持强制转换EDM基本类型或枚举类型。

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

Rob*_*Rob 5

没有模板参数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;
}
Run Code Online (Sandbox Code Playgroud)

或者,如果您希望使用它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;
}
Run Code Online (Sandbox Code Playgroud)