Использование отражений (и других не переводимых SQL) вызовов внутри дерева выражений запросов не очень хорошая идея.В EF Core 1x и 2.x это вызовет оценку клиента, а EF Core v3 + сгенерирует исключение, подобное EF 6.
LINQ to Entities лучше всего работает с выражениями.И как только вам понадобится выражение, вам лучше сделать так, чтобы ваш пользовательский метод расширения получал лямбда-выражение напрямую, а не PropertyInfo
, полученное с помощью лямбда-выражения, как в связанном разделе.
Вот пример реализации вышеуказанного:
public static partial class QueryableExtensions
{
public static IQueryable<T> WhereMatch<T>(this IQueryable<T> source, Expression<Func<T, string>> expr, string searchValue)
{
if (string.IsNullOrEmpty(searchValue))
return source;
else if (searchValue.Contains("%"))
return source.Where(expr.Map(value => EF.Functions.Like(value, searchValue)));
else
return source.Where(expr.Map(value => value == searchValue));
}
static Expression<Func<TSource, TTarget>> Map<TSource, TIntermediate, TTarget>(this Expression<Func<TSource, TIntermediate>> source, Expression<Func<TIntermediate, TTarget>> target)
=> Expression.Lambda<Func<TSource, TTarget>>(Expression.Invoke(target, source.Body), source.Parameters);
}
Основной метод - WhereMatch
.Он использует небольшой вспомогательный метод Expression
, называемый Map
, для составления лямбда-выражений из других лямбда-выражений.
Пример использования:
// SearchPerson searchPerson
// DbContext db
var query = db.Set<Person>()
.WhereMatch(p => p.Name, searchPerson.Name)
.WhereMatch(p => p.MothersName, searchPerson.MothersName)
.WhereMatch(p => p.FathersName, searchPerson.FathersName);