Lets say I have a table dataContext.Customer with the following fields
FName varchar
LName varchar
Phone varchar
DOB datetime
Using the PredicateBuilder
void Main()
{
var search = new string[] { "Romania","RO"};
var query = from c in countries.AllAny(search)
orderby c.name
select c;
query.Dump();
}
public static class QueryExtensions
{
public static IQueryable AllAny(this IQueryable query, string[] search)
{
var properties = typeof(T).GetProperties().Where(p => p.GetCustomAttributes(typeof(System.Data.Linq.Mapping.ColumnAttribute),true).Any()).Select(n=>n.Name);
var andPredicate = PredicateBuilder.True();
foreach ( var term in search )
{
var orPredicate = PredicateBuilder.False();
foreach (var property in properties )
orPredicate = orPredicate.Or(CreateLike(property,term));
andPredicate = andPredicate.And(orPredicate);
}
return query.Where(andPredicate);
}
private static Expression> CreateLike( PropertyInfo prop, string value)
{
var parameter = Expression.Parameter(typeof(T), "f");
var propertyAccess = Expression.MakeMemberAccess(parameter, prop);
var toString = Expression.Call(propertyAccess, "ToString", null, null);
var like = Expression.Call(toString, "Contains", null, Expression.Constant(value,typeof(string)));
return Expression.Lambda>(like, parameter);
}
private static Expression> CreateLike( string propertyName, string value)
{
var prop = typeof(T).GetProperty(propertyName);
return CreateLike(prop, value);
}
}
// http://www.albahari.com/nutshell/predicatebuilder.aspx
public static class PredicateBuilder
{
public static Expression> True () { return f => true; }
public static Expression> False () { return f => false; }
public static Expression> Or (this Expression> expr1,
Expression> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast ());
return Expression.Lambda>
(Expression.OrElse (expr1.Body, invokedExpr), expr1.Parameters);
}
public static Expression> And (this Expression> expr1,
Expression> expr2)
{
var invokedExpr = Expression.Invoke (expr2, expr1.Parameters.Cast ());
return Expression.Lambda>
(Expression.AndAlso (expr1.Body, invokedExpr), expr1.Parameters);
}
}
Update This code is a generic solution for the following query
from c in countries
where (c.name.ToString().Contains(search[0]) || c.name.ToString().Contains(search[1]))
&& (c.iso_code.ToString().Contains(search[0]) || c.iso_code.ToString().Contains(search[1]))
/*&& ...*/
orderby c.name
select c
This code can be improved in many ways. For sample, for the string properties, there is no need to call ToString before Contains ( this will generate a convert(nvarchar)) and I really think someone who needs this will only want to look at the varchar, nvarchar columns.