Reputation: 21615
I'm trying to create an expression tree that's similar to performing subqueries like:
SELECT (SELECT Sum(Foo) FROM Bar1) - (SELECT Sum(Foo) FROM Bar2))
I'm trying to reuse 2 expression trees that are too complex to repeat.
What I have right now is 2 (simplified) expression trees:
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();
I've already tried to use Expression.Subtract
:
Expression foo = Expression.Subtract(SumBar1, SumBar2);
This fails with the error:
The binary operator Subtract is not defined for the types 'System.Func
2[Bar,System.Int32]' and 'System.Func
2[Bar,System.Int32]'.
I also tried using Expression.Invoke
to call the trees:
Expression.Subtract( Expression.Invoke(SumBar1, Expression.Parameter(typeof(Bar)), Expression.Invoke(SumBar2, Expression.Constant(typeof(Bar))));
But then I get:
The LINQ expression node type 'Invoke' is not supported in LINQ to Entities.
Is there any way to combined the two expression trees into a new tree, subtracting them, and passing along the parameter?
Upvotes: 1
Views: 1665
Reputation: 13104
This comes up a lot when dynamically building up Linq queries for EF, and you almost got there. I've written code to do this by hand before, but doing with with LinqKit is so much easier.
Once you are using LinqKit, just write a lambda expression that invokes both subexpressions and subtracts the results. Then call "Expand" on the resulting expression and save the result. The new expression will no longe rhave the invokes because the arguments passed to the inner expressions have been substituted into their bodies and the method calls removed.
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();
Upvotes: 2
Reputation: 3997
Now I don't know EF, but LINQ, and this sounds a bit strange to me. Why do you want to subtract a delegate from another?
More appropriate would be something like:
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());
I have to make a reservation though, I haven't really tested this, and this can be totally wrong.. :)
Upvotes: 0