Я начал использовать код, который Джон Кётер опубликовал в своем блоге в другом ответе, которого больше не существует.
Однако я обнаружил, что он не работает должным образом, особенно при использовании IEnumerable
. А именно, он разрешал перечисляемое с использованием ToArray
и использовал регулярное выражение для сопоставления, а не встроенные функции.
Поскольку я хочу разрешить свой IEnumerable
только после завершения фильтрации, я внес некоторые изменения, чтобы преобразовать в IQueryable
, а затем использовать оставшуюся часть кода, чтобы найти правильный метод Entity Framework и вызвать его. Таким образом, сам запрос не вызывается для базы данных до тех пор, пока позже, и он избегает использования регулярных выражений.
public static IQueryable<T> WhereLike<T>(this IQueryable<T> source, Expression<Func<T, string>> valueSelector, string value, char wildcard)
{
return source.Where(BuildLikeExpression(valueSelector, value, wildcard));
}
public static IEnumerable<T> WhereLike<T>(this IEnumerable<T> source, Expression<Func<T, string>> valueSelector, string value, char wildcard)
{
return source.AsQueryable().WhereLike(valueSelector, value, wildcard);
}
private static Expression<Func<T, bool>> BuildLikeExpression<T>(Expression<Func<T, string>> valueSelector, string value, char wildcard)
{
if (valueSelector == null) throw new ArgumentNullException("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<T, 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 });
}
Использование:
// example data set
var data = new List<Person> {
new Person{FirstName="John", LastName="Smith"},
new Person{FirstName="Jane", LastName="Doe"}
};
data.WhereLike(x=>x.FirstName, "John", "%"); // returns John Smith
data.WhereLike(x=>x.FirstName, "J%", "%"); // returns John Smith and Jane Smith