使用现有的IQueryable创建新的动态IQueryable

时间:2010-05-27 21:00:33

标签: entity-framework linq-to-entities expression-trees iqueryable

我的查询如下:

var query = from x in context.Employees
    where (x.Salary > 0 && x.DeptId == 5) || x.DeptId == 2
    order by x.Surname
    select x;

以上是原始查询并返回让我们说1000个员工实体。

我现在想使用第一个查询来解构它并重新创建一个看起来像这样的新查询:

var query = from x in context.Employees
    where ((x.Salary > 0 && x.DeptId == 5) || x.DeptId == 2) && (x,i) i % 10 == 0
    order by x.Surname
    select x.Surname;

此查询将返回100个姓氏。

语法可能不正确,但我需要做的是附加一个额外的where子句并将select修改为单个字段。

我一直在调查ExpressionVisitor,但我不完全确定如何根据现有查询创建新查询。

任何指导都将不胜感激。谢谢你。

1 个答案:

答案 0 :(得分:0)

在表达式访问者中,您将覆盖方法调用。检查方法是否为Queryable.Where,如果是,则第二个参数是lambda表达式的带引号的表达式。将它捞出来你就可以搞定了。

    static void Main()
    {
        IQueryable<int> queryable = new List<int>(Enumerable.Range(0, 10)).AsQueryable();
        IQueryable<string> queryable2 = queryable
            .Where(integer => integer % 2 == 0)
            .OrderBy(x => x)
            .Select(x => x.ToString());
        var expression = Rewrite(queryable2.Expression);
    }

    private static Expression Rewrite(Expression expression)
    {
        var visitor = new AddToWhere();
        return visitor.Visit(expression);
    }

    class AddToWhere : ExpressionVisitor
    {
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            ParameterExpression parameter;
            LambdaExpression lambdaExpression;
            if (node.Method.DeclaringType != typeof(Queryable) ||
                node.Method.Name != "Where" ||
                (lambdaExpression = ((UnaryExpression)node.Arguments[1]).Operand as LambdaExpression).Parameters.Count != 1 ||
                (parameter = lambdaExpression.Parameters[0]).Type != typeof(int))
            {
                return base.VisitMethodCall(node);
            }
            return Expression.Call(
                node.Object,
                node.Method,
                this.Visit(node.Arguments[0]),
                Expression.Quote(
                    Expression.Lambda(
                        lambdaExpression.Type,
                        Expression.AndAlso(
                            lambdaExpression.Body,
                            Expression.Equal(
                                Expression.Modulo(
                                    parameter,
                                    Expression.Constant(
                                        4
                                    )
                                ),
                                Expression.Constant(
                                    0
                                )
                            )
                        ),
                        lambdaExpression.Parameters
                    )
                )
            );
        }
    }
}