Эффективный способ обновления списка объектов
Я работаю над проектом, который позволяет пользователю редактировать список сущностей. Я сопоставляю эти объекты для просмотра моделей и отображения их с полями редактора. Когда пользователь нажимает кнопку отправки, я просматриваю каждую модель и обновляю ее так:
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. Есть ли способ выполнить все обновления после завершения цикла?
Ответы
Ответ 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
Надеюсь, это поможет вам достичь вашего требования.
Ответ 4
HatSoft уже упоминал EntityFramework.Extended. Просто посмотрите на следующий пример, основанный на расширенной структуре.
http://weblogs.asp.net/pwelter34/archive/2011/11/29/entity-framework-batch-update-and-future-queries.aspx