Linq:Queryable.OrderBy()使用表达式集合

时间:2014-07-01 06:52:35

标签: c# linq entity-framework lambda

我想知道如何在列表中存储orderby表达式。这就是我想写的:

List<Expression<Func<Products,Object>>> list = new List<Expression<Func<Products,Object>>>()
{
  p => p.Name,
  p => p.Id
};

然后:

var expr = list[0];
myProducts.OrderBy( expr );

适用于p.Name,但不适用于p.Idlist[1]),因为它会删除异常

  

未处理的类型&#39; System.NotSupportedException&#39;发生在EntityFramework.SqlServer.dll中   附加信息:无法转换类型&System; Int32&#39;键入&#39; System.Object&#39;。 LINQ to Entities仅支持转换EDM原语或枚举类型。

我必须使用哪种类型的列表?

3 个答案:

答案 0 :(得分:1)

这是我的解决方案(使用反思并基于DynamicLinq提示):

定义ConvertableExpression课程,以便我们拦截对自定义OrderBy()的调用:

public class ConvertableExpression<T>
{
    public ConvertableExpression(Expression<Func<T, object>> expr)
    {
        this.Expression = expr;
    }

    public Expression<Func<T, object>> Expression { get; private set; }
}

引入扩展方法,以便从普通Expression

更容易地进行投射
public static class ExpressionExtensions
{
    public static ConvertableExpression<T> AsConvertable<T>(this Expression<Func<T, object>> expr)
    {
        return new ConvertableExpression<T>(expr);
    }
}

使用基于反射的IQueryable实现扩展OrderBy()

public static class QueryableExtensions
{
    public static IOrderedQueryable<T> OrderBy<T>(this IQueryable<T> source, ConvertableExpression<T> expr)
    {
        Expression queryExpr = source.Expression;

        var exprBody = SkipConverts(expr.Expression.Body);
        var lambda = Expression.Lambda(exprBody, expr.Expression.Parameters);
        var quote = Expression.Quote(lambda);

        queryExpr = Expression.Call(typeof(Queryable), "OrderBy", new[] { source.ElementType, exprBody.Type }, queryExpr, quote);

        return (IOrderedQueryable<T>)source.Provider.CreateQuery(queryExpr);
    }

    private static Expression SkipConverts(Expression expression)
    {
        Expression result = expression;

        while (result.NodeType == ExpressionType.Convert || result.NodeType == ExpressionType.ConvertChecked)
            result = ((UnaryExpression)result).Operand;

        return result;
    }
}

用法:

myProducts.OrderBy(expr.AsConvertable());

答案 1 :(得分:0)

因此看起来像EF的OrderBy的实现通过检查是否&lt; T&gt; 是一个结构或对象,所以你告诉它调用 OrderBy&lt; ...,object&gt;(someStructTypeVariable)

作为一种解决方法,我会劝你存储整个代表而不是表达。

试试这个:

internal static class MyExtensions
{
    public static IOrderedQueryable<TSource> OrderBy<TSource, TField>(this IQueryable<TSource> source, Expression<Func<TSource, TField>> selector, bool descending)
    {
        return descending 
            ? source.OrderByDescending(selector)
            : source.OrderBy(selector);
    }

}


var orderers = new List<Func<IQueryable<Products>, IOrderedQueryable<Products>>>()
    {
        source => source.OrderBy(x => x.Id, true),
        source => source.OrderBy(x => x.Id, false), 
        source => source.OrderBy(x => x.Name, false)
    };


// To be replaced with entity source-collection.
IQueryable<Products> dummySource = new EnumerableQuery<MyType>(new List<Products>());

orderers[0](dummySource.Where(x => x.Id != 0));

答案 2 :(得分:0)

试试这个

List<Func<Products, Object>> list = new List<Func<Products, Object>>()
{
    new Func<Products,Object>( p => p.Name),
    new Func<Products,Object>( p => p.Id),
};