Как избежать операторов if if в фильтре API в Linq - PullRequest
0 голосов
/ 19 апреля 2020

Я только начал разрабатывать REST API в Net Core. Я должен создать API для фильтра. Например,

Существует три таблицы: tbl_agent, tbl_tags и tbl_agent_tags_mapping

Таблица агентов имеет следующие идентификаторы столбцов, имя, company_name

Таблица тегов имеет следующие идентификаторы столбцов, имя тега

tbl_agent_tags_mapping имеет следующие идентификаторы столбцов, agent_id (FK), tag_id (FK)

  • Агенту можно назначить несколько тегов

Для фильтрации агента по тег и имя Я использую приведенный ниже код, идентификатор которого неосуществим.

IQueryable<tbl_agent> query = context.tbl_agent;

if (name != String.Empty)
{
    query = query.Where(x => x.name == name);
}

if (tags.Count > 0)
{
    var agent_ids = context.tbl_agent_tags_mapping
            .Where(x => tags.Contains(x.id))
            .Select(x => x.id).ToList();

    query = query.Where(x => agent_ids.Contains(x.job_order_id));
}

List<tbl_agent> agent_list = query.ToList();

В этом примере я взял только два параметра, но на самом деле у меня есть от 10 до 12 параметров в запросе POST API-интерфейса фильтра.

Существует ли какой-либо шаблон проектирования, позволяющий преодолеть это повторяющееся утверждение If ... Else ..?

Ответы [ 3 ]

1 голос
/ 19 апреля 2020

Лично я не знаю ни одного шаблона проектирования для этого, но я столкнулся с той же проблемой, и кое-что для улучшения (немного, а в некоторых случаях) использовал этот метод расширения:

public static IQueryable<T> WhereIf<T>(this IQueryable<T> query, Expression<Func<T, bool>> predicate, Func<bool> validation)
{
    return validation?.Invoke() == true ? query.Where(predicate) : query;
}

таким образом я могу выстроить такие условия:

var filtered = query.WhereIf(x => x.name == name, () => !string.IsNullOrEmpty(name))
                    .WhereIf(x => agent_ids.Contains(x.job_order_id), () => tags.Any()) //.Count > 0
                    .WhereIf(x => x.AnotherProperty == anotherValue, () => AnotherCondition);

Конечно, определенно будет много других вариантов, используйте тот, который лучше соответствует вашим потребностям.

Надеюсь, это поможет .-

Примечание. Я бы не советовал вам удалять тот, который связан с тегами. Количество> 0 (вы можете пометить теги. Любой (), кстати), так как этот предотвращает попадание в базу данных, что в противном случае вы будете сработать.

0 голосов
/ 19 апреля 2020

Существует ли какой-либо шаблон проектирования, позволяющий преодолеть этот повторяющийся оператор If..Else ..?

Нет. На самом деле, нет. Вы не хотите встраивать name != String.Empty или tags.Count > 0 в сам запрос, как предлагает один из других текущих ответов. Это приведет к SQL Query с предикатами вроде

where @name <> '' or name = @name
  and @otherParam is null or otherCol = @otherParam
. . .

, который является известным анти-паттерном для динамического c поиска в SQL. См. Например Dynami c Условия поиска в T- SQL. Поскольку план выполнения запроса для запроса обычно должен быть одинаковым для всех значений параметров, поэтому план не может использовать индексы для ваших искомых столбцов.

Вы делаете все правильно, добавляя только те предикаты, которые пользователь по запросу. Метод расширения @ pinedax делает этот шаблон немного чище.

0 голосов
/ 19 апреля 2020

Вы можете использовать следующее:

if (tags.Count > 0) // don't get rid of this as it is
{
    var agent_ids = context.tbl_agent_tags_mapping
            .Where(x => tags.Containd(x.id))
            .Select(x => x.id).ToList();
}
query = query.Where(x => (name == String.Empty ||x.name == name) 
    && (tags.Count == 0 || agent_ids.Contains(x.job_order_id)));

Я бы не советовал избавляться от этого состояния. Это предотвращает ненужные дб туда и обратно.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...