Как заполнять записи в Entity Framework?

Я пытаюсь выполнить массовое обновление записей с помощью Entity Framework. Я пробовал метод Entity Framework.Extensions Update.

Метод Update может выполнять массовое обновление для набора записей с одинаковым набором значений обновления.

Пример:

           Id -  Quantity
Record 1 - A  -  10
Record 2 - B  -  20
Record 3 - C  -  30

Мы можем массово обновлять все вышеупомянутые записи простым вызовом

Records.Update(new => Record { Quantity = 100 });

Как я могу Entityframework.Extensions обновлять каждую запись с помощью различного количества, используя Entityframework.Extensions или любой другой подход, который быстрее завершает массовое обновление?

Ответ 1

Если вы не хотите использовать инструкцию SQL, вы можете использовать метод Attach для обновления объекта без необходимости его первой загрузки:

using (myDbEntities db = new myDbEntities())
{
    try
    {
      //disable detection of changes to improve performance
      db.Configuration.AutoDetectChangesEnabled = false;

      //for all the entities to update...
      MyObjectEntity entityToUpdate = new MyObjectEntity() {Id=123, Quantity=100};
      db.MyObjectEntity.Attach(entityToUpdate);

      //then perform the update
      db.SaveChanges();
    }
    finally
    {
      //re-enable detection of changes
      db.Configuration.AutoDetectChangesEnabled = true;
    }
}

Ответ 2

Использовать ExecuteSqlCommand:

using (yourDbEntities db = new yourDbEntities())
{
    db.Database.ExecuteSqlCommand("UPDATE YourTABLE SET Quantity = {0} WHERE Id = {1}", quantity, id);
}

Или ExecuteStoreCommand:

yourDbContext.ExecuteStoreCommand("UPDATE YourTABLE SET Quantity = {0} WHERE Id = {1}", quantity, id);

Ответ 3

Массовое обновление может быть выполнено в три этапа с помощью простого EF вместо отдельных методов расширения:

  • Сначала загрузите все объекты.
  • Foreach на каждом объекте и измените его значения полей.
  • После Foreach сохраните изменения контекста один раз.

Это отправит несколько запросов обновления в одну партию.

Ответ 4

Я склонен сказать, что проблема здесь не в EntityFramework, а в ожидании того, как обновлять записи в SQL. Если у вас есть 50 записей, и вы хотите изменить поле "Количество" на всех из них на новое уникальное значение, вам нужно будет использовать 50 команд. AFAIK, SQL просто не имеет механизма, чтобы понять, как обновлять эти записи без отдельной команды для каждой записи. Это ограничение затем передается EF.

Тем не менее, есть несколько способов, по которым вы можете попытаться получить некоторую производительность от обновления большого количества записей:

  • Пакетное обновление. Как уже упоминалось в нескольких других ответах, вы можете использовать пакетное обновление, в котором вы сразу отправляете несколько операторов UPDATE в одной команде SQL.
  • Групповая группировка - SQL отлично справляется с обновлением нескольких строк с помощью одной команды UPDATE, если вы хотите установить поля одинакового значения во всех соответствующих записях в запросе. Вы можете использовать это в своих интересах, если вы можете группировать количество, необходимое для обновления. Например, если вы знаете, что вам нужно обновить 150 записей до количества 100, вы можете запустить это как один запрос UPDATE с предложением WHERE, чтобы включить все соответствующие идентификаторы.
  • XML файлы :( - SQL имеет кучу встроенных команд для обработки XML. Вы могли бы использовать такую команду, как UPDATE TBL SET TBL.QUANTITY = XMLTBL.QUANTITY FROM OPENXML(@idoc, '/ROOT/Items',1). Подробнее см. Https://docs.microsoft.com/en-us/sql/t-sql/functions/openxml-transact-sql.

Однако часть вопроса заключается в том, насколько важно обновлять записи так быстро, как вы можете? Конечно, мы все хотим, чтобы наши запросы были быстрыми, но если нам нужно что-то реализовать, чтобы получить эту производительность, это может не стоить в конечном счете. Например, можно ли запустить обновление в фоновом потоке, чтобы оно не блокировалось?

Ответ 5

Используйте этот способ, если вы просто хотите изменить несколько свойств:

   foreach (var vSelectedDok in doks)
                    {
                        //disable detection of changes to improve performance
                        vDal.Configuration.AutoDetectChangesEnabled = false;

                        vDal.Dokumente.Attach(vSelectedDok);

                        vDal.Entry(vSelectedDok).Property(x=>x.Status).IsModified=true;
                        vDal.Entry(vSelectedDok).Property(x => x.LastDateChanged).IsModified = true;
    }
    vDal.SaveChanges();