Подтвердить что ты не робот

Эффективный способ обновления списка объектов

Я работаю над проектом, который позволяет пользователю редактировать список сущностей. Я сопоставляю эти объекты для просмотра моделей и отображения их с полями редактора. Когда пользователь нажимает кнопку отправки, я просматриваю каждую модель и обновляю ее так:

foreach (var viewModel in viewModels)
{
    //Find the database model and set the value and update
    var entity = unit.EntityRepository.GetByID(fieldModel.ID);
    entity.Value = viewModel.Value;
    unit.EntityRepository.Update(entity);
}

Приведенный выше код работает, однако, как вы можете видеть, нам нужно дважды ударить базу данных для каждого объекта (один раз для извлечения, а другой - для обновления). Есть ли более эффективный способ сделать это с помощью Entity Framework? Я заметил, что каждое обновление генерирует отдельный оператор SQL. Есть ли способ выполнить все обновления после завершения цикла?

4b9b3361

Ответ 1

Вот два способа, которым я знаю, обновить сущность в базе данных, не выполняя сначала поиск объекта:

//Assuming person is detached from the context
//for both examples
public class Person
{
  public int Id { get; set; }
  public string Name { get; set; }
  public DateTime BornOn { get; set; }   
}

public void UpdatePerson(Person person)
{
  this.Context.Persons.Attach(person)
  DbEntityEntry<Person> entry = Context.Entry(person);
  entry.State = System.Data.EntityState.Modified;
  Context.SaveChanges();
}

Должен выдать:

Update [schema].[table]
Set Name = @p__linq__0, BornOn = @p__linq__1
Where id = @p__linq__2

Или вы можете просто указать поля, если вам нужно (возможно, полезно для таблиц с тонны столбцов или для целей безопасности, позволяет обновлять только определенные столбцы:

public void UpdatePersonNameOnly(Person person)
{
  this.Context.Persons.Attach(person)
  DbEntityEntry<Person> entry = Context.Entry(person);
  entry.Property(e => e.Name).IsModified = true;
  Context.SaveChanges();
}

Должен выдать:

Update [schema].[table]
Set Name = @p__linq__0
Where id = @p__linq__1

Ответ 2

Вы можете попытаться свести к минимуму запросы:

using (var ctx = new MyContext())
{
    var entityDict = ctx.Entities
        .Where(e => viewModels.Select(v => v.ID).Contains(e.ID))
        .ToDictionary(e => e.ID); // one DB query

    foreach (var viewModel in viewModels)
    {
        Entity entity;
        if (entityDict.TryGetValue(viewModel.ID, out entity))
            entity.Value = viewModel.Value;
    }

    ctx.SaveChanges(); //single transaction with multiple UPDATE statements
}

Помните что Contains может быть потенциально медленным, если список viewModels очень длинный. Но он будет запускать только один запрос.

Ответ 3

Я не уверен, поддерживает ли текущая версия в бета-версии или RC Entity Framework что-то вроде пакетного обновления. Но их расширение для EF 4.3.1 на Nuget

http://nuget.org/packages/EntityFramework.Extended

Надеюсь, это поможет вам достичь вашего требования.