I have an entity.
public class Foo
{
public int Id { get; set; }
public string Name { get; set; }
public string Code { get; set; }
}
I want to create my own expression predicate. For that I have created a method that accepts property name and the value.
private static Expression<Func<Foo, bool>> Condition(string pName, object value)
{
var pe = Expression.Parameter(typeof(Foo), "foo");
var left = Expression.Property(pe, pName);
var right = Expression.Constant(value);
var equal = Expression.Equal(left, right);
var predicate = Expression.Lambda<Func<Foo, bool>>(equal, pe);
return predicate;
}
This is the predicate which works fine for a single condition.
using (var db = new MyEntities())
{
var predicate = Condition("Name", "foo");
var foos = db.Foos.Where(predicate).ToArray();
}
But when I tried to combine two conditions by following this post, it throws exception.
The parameter 'foo' was not bound in the specified LINQ to Entities query expression.
using (var db = new MyEntities())
{
var cond1 = Condition("Name", "foo");
var cond2 = Condition("Code", "bar");
var body = Expression.AndAlso(cond1.Body, cond2.Body);
var predicate = Expression.Lambda<Func<Foo,bool>>(body, cond1.Parameters[0]);
var foos = db.Foos.Where(predicate).ToArray(); // exception
}
Please enlighten me.
The problem is that
ParameterExpression
in LINQ expressions is identified by reference equality, but the twoParameter
objects are different references. (Thename
inParameterExpression
only exists for debugging purposes).(If you reread the mentioned post, it says that the method that you tried would only work if both lambdas are defined on the same
ParameterExpression
object).You have two big possibilities at this stage: either you define a way for the
Condition
function to accept aParameterExpression
object, or you create anExpressionVisitor
that will replace the originalParameterExpression
with another. (Of course, given that you want to do anAndAlso
, you could also conceivably chain twoWhere
clauses, but that is less general.)