I am trying to build an expression tree dynamically to fetch data from a database.
The following codes are used for this.
Expression<Func<Client, bool>> expression = x => true;
foreach (var item in searchParams)
{
var operatorType = ExpressionType.Equal;
string propertyName = null;
object value = null;
string keyValue = item.Value;
if (item.Key == Constants.SearchParameterNames.Id)
{
int val = 0;
if (int.TryParse(keyValue, out val))
value = val;
propertyName = "ClientID";
}
else if (item.Key == Constants.SearchParameterNames.Lastupdate)
{
DateTime dateTime;
if (DateTime.TryParse(keyValue, out dateTime))
value = dateTime;
propertyName = "LastChange";
}
if (!string.IsNullOrWhiteSpace(propertyName) && value != null)
{
var exp = GetBinaryOperation<Client>(propertyName, operatorType, value);
var exp1 = Expression.And(expression.Body, exp);
expression = Expression.Lambda<Func<Client, bool>>(exp1, expression.Parameters);
}
}
var client = _clientRepository.FindBy(expression).ToList();
when _clientRepository.FindBy(expression).ToList()
is executed I am getting an exception of
The parameter 'x' was not bound in the specified LINQ to Entities query expression.
The method used to create expression:
public BinaryExpression GetBinaryOperation<T>(string propertyName, ExpressionType type, object value)
{
var parameterExpression = Expression.Parameter(typeof(T), "x");
var memberExpression = Expression.Property(parameterExpression, propertyName);
var propertyType = GetMemberType(memberExpression);
var rhs = Expression.Constant(value);
var binaryExpression = Expression.MakeBinary(type, memberExpression, rhs);
return binaryExpression;
}
When building such an expression you have to preserve the top-level parameter expression instance. When you create a new parameter expression in the GetBinaryOperation
function, that will be a different instance (hence the not bound term), regardless of the fact that its name is the same "x"
.
Instead of creating a new parameter instance, you should pass the original LambdaExpression
's "x"
parameter to the GetBinaryOperation
function using for example expression.Parameters[0]
.
All in all, you have to use the same parameter expression instance
throughout the entire expression tree in this case.