is it possible to dynamically generate such a predicate using LambdaExpressions
?
Expression<Func<Test, bool>> predicate = t =>
t.Levels.Any(l =>
l.LevelDetails.Any( ld =>
ld.LevelDate > DbFunctions.AddDays(t.TestDate, 1)
)
);
As long as the parameters in the inner BinaryExpression
are identical or the right part of the expression is constant, there is no problem. But the example expressionld.LevelDate > DbFunctions.AddDays (t.TestDate, 1)
contains two different ExpressionParameters
which are independent from each other. What I am looking for is something like this:
Expression<Func<LevelDetail, DateTime?>> left =
ld => ld.LevelDate;
Expression<Func<Test, DateTime?>> right =
t => DbFunctions.AddDays(t.TestDate, 1);
BinaryExpression expr =
Expression.GreaterThan(
((LambdaExpression)left).Body,
((LambdaExpression)right).Body
);
Expression<Func<Test, bool>> predicate = t =>
t.Levels.Any(l =>
l.LevelDetails.Any( **expr** )
);
class Test {
public DateTime TestDate { get; set; }
public virtual ICollection<Level> Levels { get; set; }
}
class Level {
public virtual ICollection<LevelDetail> LevelDetails { get; set; }
}
class LevelDetail {
public DateTime LevelDate { get; set; }
}
Kind regards!
I would recommend using nein-linq to combine, build and compose predicates (and many other expression puzzles), or LinqKit
Both support Entity Framework
For example, using nein-linq
Given:
When:
Then:
As pointed out in the answers by @Matt Warren if yow want to combine lambdas you will need to do it by hand and will need to set the correct expression parameters.
Firstlly, you will need a
ExpressionVisitor
that can replace node that you want:Secondly, you will need to combine lambdas by hand:
And the code below contains usage of this:
When you build an expression with nested lambda's the inner lambda's expressions will be able to access the outer lambda's parameters. It works the same way with Expression<T> lambdas as with regular C# lambdas.
If you are working with Expression<T> lambdas and trying to combine them, you'll need to work with them at the API level (do it by hand), and not expect the automatic C# language syntax to Expression<T> conversion to help you out.
One thing to note: when you created the two original lambdas (via conversion to Expression<T>), they each got their own ParameterExpression instances, which will make it impossible to combine them because both bodies will need to be referencing the same instance (unless you replace one for the other using an ExpressionVisitor.)