Составление запроса OR с помощью EF Core - PullRequest
0 голосов
/ 26 февраля 2019

У меня есть DbQuery, который я пытаюсь отфильтровать на основе различных (необязательных) параметров, предоставленных пользователем.Я пытаюсь составить запрос с помощью LINQ, чтобы учесть это, но натолкнулся на загвоздку, так что это как бы два участника.

Postgres: я использую postgres, поэтому у меня есть столбец массива, и я хочу иметь возможность использовать useCaseArray && entity.useCases.Тем не менее, провайдер EF в настоящее время не поддерживает это.

Я не хочу переходить к составлению всего этого в raw sql, если я могу избежать этого, поэтому я подумал, что могу сделать очень уродливо ГДЕ какэто:

WHERE (useCases.Contains(x) || useCases.Contains(y) ...)

однако я не знаю, как составить это с LINQ.Я знаю, что вы можете делать операции OR, например

query.Where(item => item.cases.Contains(x) || item.cases.Contains(y))

Однако я не могу написать это таким образом, потому что мне нужно использовать foreach / loop для массива, содержащего мои X и Y.Кто-нибудь знает, как я могу это сделать?

foreach(var usecase in request.UseCases) 
{
  query = query.Where(item => item.UseCases.Contains(usecase));
}

Это сгенерирует только длинный ряд AND, когда я хочу, чтобы все подмножество было одним ИЛИ.

Я надеюсь, что я 'удалось объяснить это соответствующим образом!С другой стороны, я хотел бы иметь возможность вставлять один компонент предложения WHERE в сырой SQL, но я думаю, что это приведет к взрыву EF Core, и звучит так, как если бы FromSQL не поддерживал WHERE просто SELECT.

ОБНОВЛЕНИЕ:

На основании комментария я попробовал это: https://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/, который работает в значительной степени фантастически:

var useCaseQuery = request.UseCases
  .Select(useCase => PredicateBuilder.Create<MyEntity>(entity => entity.UseCases.Contains(useCase)))
  .Aggregate(PredicateBuilder.Or);

query = query.Where(useCaseQuery);

Это здорово, в некотором смысле, но EFCore все еще не нравится:

The LINQ expression 'where ({[assumption].UseCases => Contains(__useCase_3)} OrElse {[assumption].UseCases => Contains(__useCase_4)})' could not be translated and will be evaluated locally.

Я думаю, что это будет хорошо для меня, но первоначальная проблема все еще остается, я хотел бы, чтобы это работало на БД.

1 Ответ

0 голосов
/ 26 февраля 2019

Итак, после некоторых полезных комментариев я попробовал FromSql

if (request.UseCases != null && request.UseCases.Count > 0)
{
  // I know UseCases is a List<int> hence why I'm just joining without escaping.
  query = query.FromSql("SELECT * FROM my_table WHERE ARRAY[" + String.Join(',', request.UseCases) + "] && use_cases");
}

Мне это не нравится на 100%, потому что теперь мой сервис знает о моей таблице таблицы и именах полей, что в значительной степени сводит на нет цель ORM.Однако для этого конкретного случая он делает то, что мне нужно, и я могу продолжать сочинять так:

if (request.Groups != null && request.Groups.Count > 0)
{
  query = query.Where(data => request.Groups.Contains(data.GroupId));
}

if (!String.IsNullOrWhiteSpace(request.Title))
{
  query = query.Where(data => EF.Functions.ILike(data.Name, $"%{request.Title}%"));
}

SQL-запрос выглядит так:

SELECT my_table.classes, my_table."group", my_table.group_id, my_table.id, my_table.name, my_table.use_cases
FROM (
    SELECT * FROM my_table WHERE ARRAY[7,4] && use_cases
) AS assumption
WHERE my_table.group_id IN (7) AND (my_table.name ILIKE @__Format_3 ESCAPE '' = TRUE)
ORDER BY my_table.name DESC

До Postgres EFДрайвер ядра обновлен, возможно, это лучшее, что я могу сделать.

...