We have create this LinqExtension class to provide a Like method to Linq. Contains is not useful for us because we would like to do searchs like "%a%b%", in StackOverFlow we have found several post that are using method PatIndex from SqlFunction class to do It with Entity Framework.
To keep clean code and easy reusable we are trying to do an extension method to encapsulate PatIndex call
public static IQueryable<TSource> WhereLike<TSource>(
this IQueryable<TSource> source,
Expression<Func<TSource, string>> valueSelector,
string value
)
{
return source.Where(BuildLikeExpression(valueSelector, value));
}
public static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>(
Expression<Func<TElement, string>> valueSelector,
string value
)
{
if (valueSelector == null)
throw new ArgumentNullException("valueSelector");
var method = GetLikeMethod(value);
var body = Expression.Call(method, valueSelector.Body, Expression.Constant(value));
var parameter = valueSelector.Parameters.Single();
var expressionConvert = Expression.Convert(Expression.Constant(0), typeof(int?));
return Expression.Lambda<Func<TElement, bool>> (Expression.GreaterThan(body, expressionConvert));
}
private static MethodInfo GetLikeMethod(string value)
{
var methodName = "PatIndex";
Type stringType = typeof(SqlFunctions);
return stringType.GetMethod(methodName);
}
The problem is when we call this new method we get the error Incorrect number of parameters supplied for lambda declaration at
return Expression.Lambda<Func<TElement, bool>> (Expression.GreaterThan(body, expressionConvert));
What are we missing to do it properly?
You're nearly there.
You've got the parameters in the wrong order for the call expression, and you need to pass the parameter to Expression.Lambda
:
public static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>( Expression<Func<TElement, string>> valueSelector, string value )
{
if ( valueSelector == null )
throw new ArgumentNullException( "valueSelector" );
var method = GetLikeMethod( value );
var body = Expression.Call( method, Expression.Constant( value ), valueSelector.Body );
var parameter = valueSelector.Parameters.Single();
var expressionConvert = Expression.Convert( Expression.Constant( 0 ), typeof( int? ) );
return Expression.Lambda<Func<TElement, bool>>( Expression.GreaterThan( body, expressionConvert ), parameter );
}