Entity Framework Поиск как или равно - PullRequest
3 голосов
/ 22 марта 2019

Я использую EntityFrameworkCore и пытаюсь создать упрощенный экземпляр поиска «равно» или «похоже» на основе того, содержит ли объект поиска подстановочный знак. Вот база того, с чем я работаю

public class Person
{
    public string Name;
    public string MothersName;
    public string FathersName;

}

public class SearchPerson
{
    public string Name;
}

public class Program
{
    public void FindPerson(SearchPerson searchPerson)
    {
        if (!string.IsNullOrEmpty(searchPerson.Name))
        {
            if (searchPerson.Name.Contains("%"))
            {
                EFPersonObject.Where(m => EF.Functions.Like(m.Name, searchPerson.Name));
            }
            else
            {
                EFPersonObject.Where(m => m.Name == searchPerson.Name);
            }
        }
    }
}

Если мой класс SearchPerson расширяется до 5, 10 или 15 возможных параметров поиска, много кода повторяется. Я должен иметь возможность реализовать некоторые отражения в расширении и использовать ответ Джима C здесь , получить и передать имя свойства и упростить его до одной строки

public static class SearchExtension
{
        public static void FindLike<T>(this DbSet<T> model, PropertyInfo info, string searchValue) where T : class
    {
        if (!string.IsNullOrEmpty(searchValue))
        {
            if (searchValue.Contains("%"))
            {
                model.Where(m => EF.Functions.Like(typeof(T).GetProperty(info.Name).GetValue(model, null).ToString(), searchValue));
            }
            else
            {
                model.Where(m => typeof(T).GetProperty(info.Name).GetValue(model, null).ToString() == searchValue);
            }
        }
    }
}

Использование:

EFPersonObject.FindLike(typeof(Person).GetProperty(RemoteMgr.GetPropertyName(()=>typeof(Person).Name)), searchPerson.Name);

(я еще не проверял это, но если это не правильно, это должно быть близко), но я собираюсь предположить, что получу удар производительности. Есть ли другой способ реализовать это, когда отражение не требуется, чтобы избежать снижения производительности?

Ответы [ 2 ]

2 голосов
/ 22 марта 2019

Использование отражений (и других не переводимых 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);
1 голос
/ 22 марта 2019

Для сравнения равенства следует использовать ==:

EFPersonObject.Where(m => m.Name == searchPerson.Name);

Для LIKE:

like 'something%': (StartsWith метод)

EFPersonObject.Where(m => m.Name.StartsWith(searchPerson.Name));

like '%something': (EndsWith метод)

EFPersonObject.Where(m => m.Name.EndsWith(searchPerson.Name));

like '%something%': (Contains метод)

EFPersonObject.Where(m => m.Name.Contains(searchPerson.Name));
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...