#entity-framework-4 #linq-to-entities #many-to-many #entitycollection #addrange
#entity-framework-4 #linq-to-entities #многие ко многим #коллекция сущностей #добавить диапазон
Вопрос:
Когда Entity Framework генерирует ObjectContext для двух таблиц базы данных (скажем, Table1 и Table2), связанных с таблицей отношений «многие ко многим», он не создает объект для таблицы внешних ссылок, вместо этого выбирая свойства коллекции на обоих концах связи. Итак, у вас есть таблица 1 EntityCollection<Table2> Table2s
и у вас есть таблица 2 EntityCollection<Table2> Table1s
. В большинстве случаев это на самом деле довольно здорово…
Однако в этом сценарии у меня есть список целых чисел, которые представляют идентификаторы базы данных строк Table2, которые должны быть в Table1.Коллекция Table2s.
Я не вижу никакого способа просто установить эту коллекцию, используя ключи сущностей, поэтому я застрял, выбирая их в ObjectContext, что уже требует тонны работы без причины. Я позволяю себе надеяться, что LINQ-to-Entities разумно отложит выполнение и выполнит все это на сервере SQL, как мне хотелось бы (хотя мое Where использует Contains, которое может быть или не быть правильно переведено в 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 не будет откладывать выполнение любого запроса. Нет ничего похожего на insert из select. Linq-to-entities — это просто язык запросов, и ответственность за выполнение запроса заключается. Это строго отделено от функциональности сохранения, предлагаемой самим EF.
Если вы хотите создать отношения между существующим элементом из table1 и выходящими элементами из table2, вы можете использовать код, подобный этому:
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
, он будет выполнять внутреннюю итерацию элементов и обрабатывать их по одному.
Комментарии:
1. Речь шла не о том, чтобы выбирать один за другим по сравнению с AddRange , за исключением наивной надежды, что вызов AddRange в этой ситуации (если бы он существовал) не вызвал бы операторов SELECT, из которых мне не нужна никакая информация (поскольку у меня уже есть идентификаторы EntityKey), Подход создания экземпляров новых объектов Table2 и вызова Attach должен сработать. Спасибо