Skip to content

Instantly share code, notes, and snippets.

@MoienTajik
Last active December 13, 2017 11:18
Show Gist options
  • Save MoienTajik/40b29c6fa65baa2dd44127d588bda395 to your computer and use it in GitHub Desktop.
Save MoienTajik/40b29c6fa65baa2dd44127d588bda395 to your computer and use it in GitHub Desktop.
Wildcard Search Helper Entity Framework

Wildcard Search Helper Entity Framework

You can build a LIKE statement with wildcard characters in LINQ to Entities with this Helper.

WildCard

public static class LinqHelper
{
public static IQueryable<TSource> WhereLike<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, string>> valueSelector, string value, char wildcard)
{
return source.Where(BuildLikeExpression(valueSelector, value, wildcard));
}
public static IEnumerable<TSource> WhereLike<TSource>(this IEnumerable<TSource> sequence, Func<TSource, string> expression, string value, char wildcard)
{
var regEx = WildcardToRegex(value, wildcard);
// Prevent multiple enumeration :
var arraySequence = sequence as TSource[] ?? sequence.ToArray();
try
{
return arraySequence.Where(item => Regex.IsMatch(expression(item), regEx));
}
catch (ArgumentNullException)
{
return arraySequence;
}
}
private static string WildcardToRegex(string value, char wildcard)
{
return "(?i:^" + Regex.Escape(value).Replace(@"\" + wildcard, "." + wildcard) + "$)";
}
private static Expression<Func<TElement, bool>> BuildLikeExpression<TElement>(Expression<Func<TElement, string>> valueSelector, string value, char wildcard)
{
if (valueSelector == null) throw new ArgumentNullException(nameof(valueSelector));
var method = GetLikeMethod(value, wildcard);
value = value.Trim(wildcard);
var body = Expression.Call(valueSelector.Body, method, Expression.Constant(value));
var parameter = valueSelector.Parameters.Single();
return Expression.Lambda<Func<TElement, bool>>(body, parameter);
}
private static MethodInfo GetLikeMethod(string value, char wildcard)
{
var methodName = "Equals";
var textLength = value.Length;
value = value.TrimEnd(wildcard);
if (textLength > value.Length)
{
methodName = "StartsWith";
textLength = value.Length;
}
value = value.TrimStart(wildcard);
if (textLength > value.Length)
{
methodName = methodName == "StartsWith" ? "Contains" : "EndsWith";
}
var stringType = typeof(string);
return stringType.GetMethod(methodName, new[] { stringType });
}
}
public class CitiesController : Controller
{
private readonly ApplicationDbContext _db = new ApplicationDbContext();
[HttpGet]
public ActionResult Index()
{
return View(_db.Cities.ToList());
}
[HttpPost]
public ActionResult Index(string searchTerm)
{
var cities = _db.Cities.AsQueryable();
if (!string.IsNullOrWhiteSpace(searchTerm))
{
searchTerm = $"%{searchTerm}%";
// OR
//searchTerm = $"%{searchTerm}";
//searchTerm = $"{searchTerm}%";
cities = cities.WhereLike(x => x.Name, searchTerm, '%');
}
return View("Index", cities.ToList());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment