Как я могу эффективно установить EntityCollection «многие ко многим» в Entity Framework?

Когда Entity Framework создает ObjectContext для двух таблиц базы данных (скажем, Table1 и Table2), связанных с таблицей отношений «многие ко многим», он не создает объект для таблицы внешних ссылок, вместо этого выбирая свойства коллекции на обоих концах таблицы. отношения. Итак, в таблице 1 у вас есть EntityCollection<Table2> Table2s, а в таблице 2 у вас есть EntityCollection<Table2> Table1s. В большинстве случаев это даже здорово...

Однако в этом сценарии у меня есть список целых чисел, представляющих идентификаторы базы данных строк Table2, которые должны быть в коллекции 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-entities — это просто язык запросов, и ответственность за запрос заключается в его выполнении. Он строго отделен от функций сохранения, предлагаемых самим 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, он будет внутренне перебирать элементы и обрабатывать их по одному.

person Ladislav Mrnka    schedule 30.05.2011
comment
Речь шла не о сравнении один за другим с AddRange, за исключением наивной надежды на то, что вызов AddRange в этой ситуации (если он существует) не приведет к операторам SELECT, из которых мне не нужна никакая информация (поскольку у меня уже есть идентификаторы EntityKey Ids). ) Подход с созданием экземпляров новых объектов Table2 и вызовом Attach должен работать. Спасибо - person Grank; 15.02.2012