using System.Linq.Expressions;
using System.Collections.Generic;
var data = new List<TestPerson>()
new TestPerson { FirstName="Aga", LastName= "Mulac", City=null, BirthDate = DateTime.Now.AddYears(-3) },
new TestPerson { FirstName="Lito", LastName="Lapid", City="Pampanga", BirthDate = DateTime.Now.AddYears(-2).AddMonths(-5) },
new TestPerson { FirstName="Almira", LastName = "Sanchez", City="Ilocos", BirthDate = DateTime.Now.AddYears(-1) },
new TestPerson { FirstName="Ala", LastName="Ali", City="Aluli", BirthDate = DateTime.Now.AddMonths(-9) }
var result = data.Relevant("al");
result.ToList().ForEach(m=> Console.WriteLine(m.ToString()));
var resultAny = data.Relevant("lito al",false);
resultAny.ToList().ForEach(m=> Console.WriteLine(m.ToString()));
public static class IQueryableExtensions
public static IQueryable<T> Relevant<T>(this IQueryable<T> qry, string keyword, bool AllKeywordMustExist = true, char keywordSeparator = ' ')
var parameter = Expression.Parameter(typeof(T), "relev");
var objectType = typeof(T);
var stringProperties = objectType.GetProperties().Where(m => m.PropertyType == typeof(string));
var keywords = keyword.Split(keywordSeparator)
.Where(m => !string.IsNullOrEmpty(m))
.Select(m => m.ToLower())
Expression completeExpression = Expression.Constant(AllKeywordMustExist);
foreach (var keywordExpression in keywords.Select(m => Expression.Constant(m)))
Expression keywordCompleteExpression = Expression.Constant(false);
foreach (var prop in stringProperties)
var containExpression = CreatePropertyContainExpression(parameter, prop, keywordExpression);
var notNullExpression = Expression.NotEqual(Expression.PropertyOrField(parameter, prop.Name), Expression.Constant(null));
var notNullContaintExpression = Expression.Condition(notNullExpression, containExpression, Expression.Constant(false));
keywordCompleteExpression = Expression.Or(keywordCompleteExpression, notNullContaintExpression);
completeExpression = Expression.And(completeExpression, keywordCompleteExpression);
completeExpression = Expression.Or(completeExpression, keywordCompleteExpression);
return qry.Where(Expression.Lambda<Func<T, bool>>(completeExpression, parameter));
private static Expression CreatePropertyContainExpression(Expression instance, PropertyInfo instanceProperty, Expression keyword)
var containMethod = typeof(string).GetMethods().FirstOrDefault(m => m.Name == "Contains" && m.GetParameters().Length == 1);
var toLowerMethod = typeof(string).GetMethods().FirstOrDefault(m => m.Name == "ToLower" && m.GetParameters().Length == 0);
var propParam = Expression.PropertyOrField(instance, instanceProperty.Name);
var tolowerExp = Expression.Call(propParam, toLowerMethod);
var containExpression = Expression.Call(tolowerExp, containMethod, keyword);
return containExpression;
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public DateTime BirthDate { get; set; }
public override string ToString()
return LastName + ", " + FirstName + " " + BirthDate.ToShortDateString() + " " + City;