I have the following code which returns a list of six objects correctly
var items = db.items.take(100);
var result = items.Where(m => m.Cost.ToString().ToLower().Contains("67.5")).ToList(); //returns 6 items
I'm trying to do the same thing using dynamic expressions.
// Print out the expression.
// .ToString() returns "m => m.Cost.ToString().ToLower().Contains("67.5")"
var whereClause = ContainsPredicate<item>("Cost", "67.5");
var result = items.Where(whereClause).ToList(); //returns 0 items
When I tries to use sql profiler to see what was being sent to the DB I noticed that it removes my clause and adds WHERE 0 = 1
ContainsPredicate method implementation :
public static Expression<Func<T, bool>> ContainsPredicate<T>(string memberName, string searchValue)
{
var parameter = Expression.Parameter(typeof(T), "m");
var member = Expression.PropertyOrField(parameter, memberName);
MethodCallExpression memberToString = Expression.Call(Expression.Constant(member), member.GetType().GetMethod("ToString", Type.EmptyTypes));
MethodCallExpression memberToLower = Expression.Call(memberToString,"ToLower", null);
var body = Expression.Call(memberToLower,"Contains",Type.EmptyTypes,Expression.Constant(searchValue));
return Expression.Lambda<Func<T, bool>>(body, parameter);
}
Any advice is appreciated. Thanks.
public static void Test()
{
var myItem = new Item() { Cost = 67.5 };
var items = new List<Item> { myItem };
var result = items.Where(m =>
m.Cost.ToString().ToLower().
Contains("67,5")).ToList();
var whereClause = ContainsPredicate<Item>("Cost", "67,5");
// var test1 = whereClause(myItem);
var result2 = items.Where(whereClause).ToList(); // returns 1 result in my case
}
public static Func<T, bool> ContainsPredicate<T>(string memberName, string searchValue)
{
var parameter = Expression.Parameter(typeof(T), "m");
var member = Expression.PropertyOrField(parameter, memberName);
// Mistake was here:
var doubleToStr = member.Type.GetMethod("ToString", Type.EmptyTypes);
MethodCallExpression memberToString = Expression.Call(member, doubleToStr);
MethodCallExpression memberToLower =
Expression.Call(memberToString, "ToLower", null);
var body = Expression.Call(memberToLower, "Contains", Type.EmptyTypes
, Expression.Constant(searchValue));
var lamb = Expression.Lambda<Func<T, bool>>(body, parameter);
// we need to compile
return lamb.Compile();
}
First thing i did was only compile memberToLower
and that returned the string "m.cost" instead of your double. "m.cost" will obviously never contain "67.5". So there you go.
Are you sure you don't want something like this:
public static Func<T, bool> ContainsPredicate2<T>(string memberName, string searchValue)
{
var prop = typeof(T).GetProperty(memberName);
Func<T, bool> func = (T obj2) =>
prop.GetValue(obj2).ToString().ToLower().Contains(searchValue);
return func;
}