Проверьте, содержит ли список элемент из другого списка в EntityFramework
У меня есть объект Person, у которого есть список мест, связанных с ним. Мне нужно запросить таблицу лиц и получить все те, у которых есть хотя бы одно местоположение из списка мест (критериев). Следующие работы но очень неэффективны:
var searchIds = new List<int>{1,2,3,4,5};
var result = persons.Where(p => p.Locations.Any(l => searchIds.Any(id => l.Id == id)));
Это отлично подходит для небольших списков (скажем, 5-10 поисковых запросов и человека с 5-10 местами. Проблема заключается в том, что у некоторых людей может быть 100 мест, а поиск также может быть в 100 местах одновременно. выполнить вышеописанный EF фактически создал SQL-запрос 2000+ и завершился неудачно, потому что он слишком глубоко вложен. В то время как вложенность уже сама по себе является проблемой, даже если бы это сработало, мне все равно не было бы очень повезло бы с SQL-запросом 2000+.
Примечание: реальный код также включает в себя несколько уровней и отношения родитель-потомок, но мне удалось получить его до этой довольно плоской структуры, используя только id, а не полные объекты
Каким будет лучший способ выполнить это в EF?
Ответы
Ответ 1
Я предлагаю:
var searchIds = new List<int>{1,2,3,4,5};
var result = persons.Where(p => p.Locations.Any(l => searachIds.Contains(l.Id)));
Contains
будет переведен в оператор IN
.
Имейте в виду, что список id входит в оператор sql. Если ваш список идентификаторов огромен, тогда вы получите огромный запрос.
Ответ 2
Попробуйте переключиться на соединения, а не массивные данные:
var searchIds = new List<int>{1,2,3,4,5};
var results = (from p in persons
join l in Location on p.PersonId equals l.PersonId
where searchIds.Contains(l.Id)
select p).Distinct().ToList();
Очевидно, исправить эту строку в соответствии с вашими классами и/или соединить свойство.
join l in Location on p.PersonId equals l.PersonId
Я ожидаю, что для создания более дружественного плана выполнения.