Как я могу изменить это для передачи в «Свойство для использования» в этой лямбде, чтобы сделать этот метод многоразовым? - PullRequest
0 голосов
/ 07 февраля 2020

На моей веб-странице есть несколько текстовых полей, в которые пользователи могут вводить сложные запросы. Сложный запрос может содержать любой из следующих Parameter s:

  1. XX*, который соответствует всему , начиная с XX
  2. *XX для всего заканчивается XX
  3. *XX* для всего , содержащего XX
  4. XX123-XX129 для всего, что соответствует диапазону включительно от XX123 до XX129
  5. XX444 для точного индивидуального значения
  6. ... любая запятая комбинация любого / всего вышеперечисленного

Реализация, которая не является моей проблема; Моя проблема заключается в реализации его для нескольких значений в многократно используемом порядке.

Пример ниже фильтрует Items для свойства Item.Value.

public static IQueryable<Item> WithMatchingItemValues(this IQueryable<Item> items,
    IEnumerable<Parameter> itemValues)
{
    var parameters = (itemValues ?? Enumerable.Empty<Parameter>()).ToList();
    if (parameters.IsEmpty()) return items;

    var (wildCards, exactMatches) = parameters.SplitOnWildCards();

    var predicate = PredicateBuilder.New<Item>(); // https://github.com/scottksmith95/LINQKit

    wildCards.ForEach(wc =>
    {
        switch (wc)
        {
            case WildCardStartsWith startsWith:
                predicate = predicate.Or(s => s.Value.ToUpper().StartsWith(startsWith.ToString()));
                break;
            case WildCardContains contains:
                predicate = predicate.Or(s => s.Value.ToUpper().Contains(contains.ToString()));
                break;
            case WildCardEndsWith endsWith:
                predicate = predicate.Or(s => s.Value.ToUpper().EndsWith(endsWith.ToString()));
                break;
        }
    });

    if (exactMatches.Any())
        predicate = predicate.Or(s => exactMatches.Select(p => p.Value).Contains(s.Value.ToUpper()));

    return items.AsExpandableEFCore().Where(predicate);
}

Как я могу реорганизовать это, чтобы я мог "передать" Item.Value методу, чтобы я мог также передать Item.PartNumber или Item.Foo без дублирования всего этого кода для каждое свойство, которое я хочу отфильтровать? Я не могу просто передать Item.Value ... это просто строка, и она не будет работать в лямбда-выражениях.

1 Ответ

1 голос
/ 07 февраля 2020

Напишите ваш метод, чтобы взять ExpressionLambda, который представляет ссылку на поле:

public static IQueryable<Item> WithMatchingItemValues(this IQueryable<Item> items,
    IEnumerable<Parameter> itemValues,
    Expression<Func<Item,string>> field)

Затем в коде, который должен ссылаться на поле, используйте метод LINQKit Invoke:

case WildCardStartsWith startsWith:
    predicate = predicate.Or(s => field.Invoke(s).ToUpper().StartsWith(startsWith.ToString()));

Наконец, используйте метод LINQKit Expand для встроенного расширения ссылок field или используйте AsExpandable, как у вас в источнике данных:

if (exactMatches.Any())
    predicate = predicate.Or(s => exactMatches.Select(p => p.Value).Contains(field.Invoke(s).ToUpper()));

return items.AsExpandableEFCore().Where(predicate);
...