Использование существующего IQueryable для создания нового динамического IQueryable - PullRequest
0 голосов
/ 28 мая 2010

У меня следующий запрос:

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 и изменить выделение в одном поле.

Я искал ExpressionVisitor , но я не совсем уверен, как создать новый запрос на основе существующего запроса.

Любое руководство будет оценено. Спасибо тебе.

1 Ответ

0 голосов
/ 26 февраля 2011

В посетителе выражения вы должны переопределить вызов метода. Проверьте, является ли метод Queryable.Where, и если да, то вторым параметром метода является выражение в кавычках типа лямбда-выражения. Выловите это, и вы можете винт с ним.

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