EF Core запрос, где предложение является коллекцией? - PullRequest
0 голосов
/ 23 января 2019

Я пытаюсь создать нормальный запрос в EF Core, который возвращает коллекцию вещей, которые, в свою очередь, получены из коллекции вещей.В основном в сыром SQL можно было бы выполнить JOIN.

Это в ASP.NET Core, поэтому начальная коллекция представляет собой список ролей объекта SecurityPrincipal:

var roles = User.FindAll(ClaimTypes.Role).Select(r=>r.Value);

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

var groupsQuery = dbContext.Groups.Where(g=>roles.Any(r=>r==g.GroupName));
var groups = await groupsQuery.ToListAsync();

Этот запрос вполне устраивает и возвращает коллекцию групп, как и ожидалось.Тем не менее, группы имеют доступ к другому ресурсу, который мне действительно нужен, и потому что существует отношение многих ко многим, существует таблица мостов.

Это я пытаюсь запросить таблицу присоединения AssetGroup, чтобы я мог получить всеАктивы, на которые ссылаются все группы, сопоставленные с ролью в SecurityPrincipal.

var assetGroupsQuery = dbContext.AssetsGroups.Where(ag => groupsQuery.Any(ag => ag.Id == a.GroupId));
var assetGroups = await assetGroupsQuery.ToListAsync();

Когда я выполняю второй запрос, в окне вывода появляется много спама:

  The LINQ expression 'where ([ag].Id == [ag].GroupId)' could not be translated and will be evaluated locally.
  The LINQ expression 'Any()' could not be translated and will be evaluated locally.
  The LINQ expression 'where {from Group g in __groups_0 where ([ag].Id == [ag].GroupId) select [ag] => Any()}' could not be translated and will be evaluated locally.
  The LINQ expression 'where ([ag].Id == [ag].GroupId)' could not be translated and will be evaluated locally.
  The LINQ expression 'Any()' could not be translated and will be evaluated locally.

Есть ли какие-либо подсказки о том, как следует формулировать вложенный запрос, подобный этому, чтобы EF Core мог правильно составлять один SQL-запрос?

1 Ответ

0 голосов
/ 23 января 2019

Как правило, избегайте использования Any или любого другого оператора LINQ, кроме Contains для в коллекции памяти , например, вашего roles (который согласно коду должен иметь тип IEnumerable<string>).

Другими словами, вместо

.Where(g => roles.Any(r => r == g.GroupName))

использовать функционально эквивалентный

.Where(g => roles.Contains(g.GroupName))

Последнее гарантированно будет переведено в SQL IN, а первое - нет.

Интересно и в то же время вводит в заблуждение тот факт, что EF Core пытается быть умным и переводить первое так же, как и Contains, и добивается успеха при выполнении содержащего запроса, но не при использовании в качестве части другого запроса.

Это можно считать текущим дефектом реализации EF Core. Но обходной путь / решение - это (как уже упоминалось в начале) не полагаться на него и всегда использовать Contains.

...