Арифметические операции над подзапросами с использованием Expression.Subtract (?) - PullRequest
1 голос
/ 20 октября 2010

Я пытаюсь создать дерево выражений, которое похоже на выполнение подзапросов, таких как:

SELECT (SELECT Sum(Foo) FROM Bar1) - (SELECT Sum(Foo) FROM Bar2))

Я пытаюсь повторно использовать 2 дерева выражений, которые слишком сложны для повторения.

Сейчас у меня есть 2 (упрощенных) дерева выражений:

Expression<Func<Bar, int>> SumBar1 =
    (bar) => (from b in bar.Something
              where b.Type = 1
              select b).Sum();

Expression<Func<Bar, int>> SumBar2 =
    (bar) => (from b in bar.Something
              where b.Type = 2
              select b).Sum();

Я уже пытался использовать Expression.Subtract:

Expression foo = Expression.Subtract(SumBar1, SumBar2);

Это происходит с ошибкой:

Бинарный оператор Subtract не является определены для типов 'System.Func 2[Bar,System.Int32]' and 'System.Func 2 [Бар, System.Int32]'.

Я также пытался использовать Expression.Invoke для вызова деревьев:

Expression.Subtract ( Expression.Invoke (SumBar1, Expression.Parameter (typeof (Bar)), Expression.Invoke (SumBar2, Expression.Constant (typeof (Bar))));

Но тогда я получаю:

Тип узла выражения LINQ 'Invoke' не поддерживается в LINQ to Entities.

Есть ли способ объединить два дерева выражений в новое дерево, вычитая их и передавая параметр?

Ответы [ 2 ]

2 голосов
/ 22 октября 2010

Это часто встречается при динамическом построении запросов Linq для EF, и вы почти достигли цели. Я написал код, чтобы сделать это вручную, но с LinqKit работать намного проще.

Как только вы используете LinqKit, просто напишите лямбда-выражение, которое вызывает оба подвыражения и вычитает результаты. Затем вызовите «Expand» в полученном выражении и сохраните результат. Новое выражение не изменится, поскольку аргументы, переданные внутренним выражениям, были подставлены в их тела, а вызовы методов удалены.

Expression<Func<Bar, int>> SumBar1 = 
    (bar) => (from b in bar.Something 
              where b.Type = 1 
              select b).Sum(); 

Expression<Func<Bar, int>> SumBar2 = 
    (bar) => (from b in bar.Something 
              where b.Type = 2 
              select b).Sum();

Expression<Func<Bar, int>> Combined = (bar) => SumBar1.Invoke(bar) - SumBar2.Invoke(bar);
Expression<Func<Bar, int>> Result = Combined.Expand();
0 голосов
/ 20 октября 2010

Теперь я не знаю EF, но LINQ, и это звучит немного странно для меня.Почему вы хотите вычесть делегата из другого?

Более подходящим было бы что-то вроде:

Expression<Func<Bar, int>> sumBar1 =
    (bar) => (from b in bar.Something
              where b.Type = 1
              select b).Sum();

Expression<Func<Bar, int>> sumBar2 =
    (bar) => (from b in bar.Something
              where b.Type = 2
              select b).Sum();

Expression<Func<Bar, int>> totalSum =
    bar =>
              sumBar1(bar) - sumBar2(bar);

totalSum(DB.GetBar());

Я должен сделать оговорку, хотя я на самом деле не проверял это,это может быть совершенно неправильно ..:)

...