Присоединение в коллекции памяти и EntityFramework
Есть ли какой-либо механизм для создания JOIN между коллекцией памяти и структурой сущности при сохранении порядка.
То, что я пытаюсь сделать,
var itemsToAdd =
myInMemoryList.Join(efRepo.All(), listitem => listitem.RECORD_NUMBER,
efRepoItem => efRepoItem.RECORD_NUMBER, (left, right) => right);
который дает мне довольно любопытное название "Этот метод поддерживает инфраструктуру LINQ to Entities и не предназначен для непосредственного использования из вашего кода". ошибка.
Теперь, конечно, я могу сделать это итеративно с чем-то вроде
foreach (var item in myInMemoryList)
{
var ho = efRepo.Where(h => h.RECORD_NUMBER == item.RECORD_NUMBER).FirstOrDefault();
tmp.Add(ho);
}
но это запрос N + 1. Что неприятно, так как myInMemoryList может быть довольно большим!
Resharper может реорганизовать, что для меня
tmp = (from TypeOfItemInTheList item in myInMemoryList
select efRepo.Where(h => h.RECORD_NUMBER == item.RECORD_NUMBER)
.FirstOrDefault());
который, как я подозреваю, все еще выполняет N + 1 запросов. Итак, любые идеи для лучшего подхода к получению ef-сущностей, которые соответствуют (в ключевом поле) с коллекцией в памяти. Результирующий набор должен быть в том же порядке, что и в ячейке памяти.
Ответы
Ответ 1
Нет, вы не можете присоединиться к коллекции в памяти с набором результатов базы данных без загрузки всего набора результатов в память и выполнения соединения с linq-to-objects. Попробуйте использовать contains вместо join:
var myNumbers = myInMemoryList.Select(i => i.RECORD_NUMBER);
var itemsToAdd = efRepo.Where(e => myNumbers.Contains(e.RECORD_NUMBER));
Это вызовет запрос с оператором IN
Ответ 2
Вы можете прочитать, как это сделать с помощью PredicateBuilder из LINQKit или хранимых процедур в моем сообщении в блоге.
http://kalcik.net/2014/01/05/joining-data-in-memory-with-data-in-database-table/
Ответ 3
попробуйте следующее:
var list = (from n in efRepo
where myInMemoryList.Select(m=>m.RECORD_NUMBER).Contains(n.RECORD_NUMBER)
select n).ToList();
Contains
будет переведен в оператор IN
в SQL (только если ваш член RECORD_NUMBER
является примитивным типом типа int
, string
, Guid
и т.д.)
Ответ 4
Как насчет загрузки всего efRepo? Я имею в виду что-то вроде этого (ToArray()):
var itemsToAdd = myInMemoryList.Join(
efRepo.ToArray(),
listitem => listitem.RECORD_NUMBER, efRepoItem => efRepoItem.RECORD_NUMBER, (left, right) => right);