Как эффективно установить коллекцию EntityCollection "многие ко многим" в Entity Framework?
Когда Entity Framework генерирует ObjectContext для двух таблиц базы данных (скажем, Table1 и Table2), связанных с таблицей отношений "многие ко многим", он не создает объект для таблицы внешних ссылок, выбирая вместо этого свойства коллекции на любом конце отношения. Итак, на Table1 у вас есть EntityCollection<Table2> Table2s
и на Table2 у вас есть EntityCollection<Table2> Table1s
, В большинстве случаев это действительно здорово...
Однако в этом сценарии у меня есть список целых чисел, которые представляют идентификаторы базы данных строк таблицы 2, которые должны быть в коллекции Table1.Table2s.
Я не вижу никакого способа просто установить эту коллекцию, используя ключи сущностей, поэтому я застрял, выбирая их в ObjectContext, а это уже тонна работы без всякой причины. Я позволю себе надеяться, что LINQ-to-Entities будет интеллектуально откладывать выполнение и выполнять все это на сервере SQL так, как мне бы хотелось (хотя мое "Где" содержит "Содержит", которое может или не может быть корректно переведено в IN() в SQL). Так что я могу пойти так далеко, как:
table1instance.Table2s.Clear();
var table2sToInclude = context.Table2s.Where(
t =>
listOfTable2DatabaseIds.Contains(t.Id));
Но нет EntityCollection<T>.AddRange(IEnumerable<T>)
или что-нибудь, и нет IEnumerable<T>.ToEntityCollection<T>()
конечно, метод расширения, поэтому я не знаю, что делать с этими результатами на данный момент. Все, что я могу сделать, это
foreach (var table2 in table2sToInclude)
{
table1instance.Table2s.Add(table2);
}
что кажется смешным, и я знаю, заставит много ненужных оценок.
Есть ли "правильный" или, возможно, "менее отстойный" способ сделать это?
1 ответ
Нет EF не будет откладывать выполнение любого запроса. Там нет ничего, как вставить из выбора. Linq-to-entity - это просто язык запросов, и ответственность за его выполнение заключается в выполнении. Он строго отделен от постоянных функций, предлагаемых самой EF.
Если вы хотите создать отношения между существующим элементом из таблицы1 и выходом из таблицы из таблицы2, вы можете использовать такой код:
using (var ctx = new YourContext())
{
var table1 = new Table1 { Id = 123 };
ctx.Table1s.Attach(table1);
foreach (var table2 in table2sToInclude.Select(id => new Table2 { Id = id }))
{
ctx.Table2s.Attach(table2);
order.Table2s.Add(table2);
}
ctx.SaveChanges();
}
Этот код создает связь между элементом Table1 с идентификатором 123 и всеми элементами Table2 из table2sToInclude без загрузки какой-либо отдельной записи из базы данных.
Что делает добавление записей по одной "хромой"? Вы понимаете, в чем выгода AddRange
? AddRange
В типичной коллекции расширяется емкость внутреннего массива и просто копируются элементы в расширенный массив. EntityCollection
не является типичным массивом, и он должен обрабатывать каждую добавленную сущность. Так что даже если будут некоторые AddRange
он будет внутренне повторять элементы и обрабатывать их по одному.