Как эффективно установить коллекцию 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 он будет внутренне повторять элементы и обрабатывать их по одному.

Другие вопросы по тегам