I am trying to convert a DateTime to a String before calling contains on it. However despite my efforts of putting the result of one expression into another I fail miserably.
The code is derived from the highest answer to this question jqgrid with asp.net webmethod and json working with sorting, paging, searching and LINQ — but needs dynamic operators.
Assume I have the following method as StringExtension from the question:
public static class StringExtensions
{
public static MemberExpression ToMemberExpression(this string source, ParameterExpression p)
{
if (p == null)
throw new ArgumentNullException("p");
string[] properties = source.Split('.');
Expression expression = p;
Type type = p.Type;
foreach (var prop in properties)
{
var property = type.GetProperty(prop);
if (property == null)
throw new ArgumentException("Invalid expression", "source");
expression = Expression.MakeMemberAccess(expression, property);
type = property.PropertyType;
}
return (MemberExpression)expression;
}
}
Therefore I have the following method also from the question which I have then adapted for DateTime.
public virtual Expression<Func<T, bool>> CreateExpression<T>(string searchField, string searchString, string searchOper)
{
Expression exp = null;
var p = Expression.Parameter(typeof(T), "p");
Expression propertyAccess = searchField.ToMemberExpression(p);
switch (searchOper)
{
case "bw":
exp = Expression.Call(propertyAccess, typeof(string).GetMethod("StartsWith", new Type[] { typeof(string) }), Expression.Constant(searchString));
break;
// New code by me
case "cn":
if (propertyAccess.Type == typeof(DateTime))
{
// My faulty logic - from Jon Skeet answer below
Expression toStringCall = Expression.Call(
propertyAccess, "ToString",
null,
new[] { Expression.Constant("D") });
Expression containsCall = Expression.Call(
toStringCall, "Contains",
null,
new[] { Expression.Constant(searchString) });
exp = containsCall;
}
else
{
// Unchanged
exp = Expression.Call(propertyAccess, typeof(string).GetMethod("Contains", new Type[] { typeof(string) }), Expression.Constant(searchString));
}
break;
case "ew":
exp = Expression.Call(propertyAccess, typeof(string).GetMethod("EndsWith", new Type[] { typeof(string) }), Expression.Constant(searchString));
break;
case "gt":
exp = Expression.GreaterThan(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
case "ge":
exp = Expression.GreaterThanOrEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
case "lt":
exp = Expression.LessThan(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
case "le":
exp = Expression.LessThanOrEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
case "eq":
exp = Expression.Equal(propertyAccess, Expression.Constant(searchString.ToType(propertyAccess.Type), propertyAccess.Type));
break;
case "ne":
exp = Expression.NotEqual(propertyAccess, Expression.Constant(searchString, propertyAccess.Type));
break;
default:
return null;
}
return (Expression<Func<T, bool>>)Expression.Lambda(exp, p);
}
I get the following exception.
LINQ to Entities does not recognize the method 'System.String ToString(System.String)' method, and this method cannot be translated into a store expression.