Предполагая, что _db
является производным от ObjectContext
, у вас есть два варианта:
Измените состояние объекта на Modified
:
_db.Movies1.Attach(movie);
_db.ObjectStateManager.ChangeObjectState(movie, EntityState.Modified);
_db.SaveChanges();
Это помечает все свойства movie
как измененные и отправляет инструкцию UPDATE в базу данных, которая включает все значения столбцов, независимо от того, действительно ли значения были изменены или нет.
Перезагрузите исходную сущность из базы данных и примените к ней изменения:
var originalMovie = (from m in _db.Movies1
where m.Id == movie.Id
select m).First();
// You actually don't need to assign to a variable.
// Loading the entity into the context is sufficient.
_db.Movies1.ApplyCurrentValues(movie);
_db.SaveChanges();
ApplyCurrentValues
помечает только те свойства, которые были изменены, которые действительно изменились по сравнению с оригиналом, а оператор UPDATE, который будет отправлен в базу данных, включает только измененные значения столбца. Таким образом, оператор UPDATE потенциально меньше, чем в первом примере, но вы должны заплатить цену, чтобы перезагрузить исходную сущность из базы данных.
Редактировать
Как работает второй пример кода?
При запуске запроса с использованием контекста (_db
) Entity Framework не только извлекает объект из базы данных и присваивает его левой стороне запроса (originalMovie
), но фактически сохраняет вторая ссылка внутри. Вы можете думать об этом внутреннем контексте «кеш» как о словаре пар ключ-значение - ключ - это первичный ключ сущности, а значение - сама сущность, тот же объект, к которому относится originalMovie
.
ApplyCurrentValues(movie)
ищет эту сущность во внутреннем словаре контекста: она принимает значение свойства ключа Id
переданного в movie
, ищет сущность с этим ключом во внутреннем словаре и затем копирует свойство за свойством от переданного («отделенного») movie
к внутреннему («присоединенному») объекту с тем же ключом. Механизм отслеживания изменений EF помечает свойства как Modified
, которые на самом деле были разными, чтобы позже создать соответствующий оператор UPDATE.
Из-за этой внутренней ссылки на исходную сущность вам не нужно хранить собственную ссылку: по этой причине originalEntity
не используется в коде. Фактически вы можете полностью удалить присвоение локальной переменной.
Пример не будет работать, если вы отключите отслеживание изменений при загрузке исходного объекта - например, установив _db.Movies1.MergeOption = MergeOption.NoTracking;
. Пример основан на включенном отслеживании изменений (это настройка по умолчанию, когда объекты загружаются из базы данных).
Я не могу сказать, какой из двух примеров имеет лучшую производительность. Это может зависеть от таких деталей, как размер объектов, количество измененных свойств и т. Д.
Следует отметить, что оба подхода не работают, если в них вовлечены связанные объекты (например, movie
относится к объекту категории) и если отношение или сам связанный объект могли быть изменены. Установка состояния Modified
и использование ApplyCurrentValues
влияют только на скалярные и сложные свойства movie
, но не на свойства навигации.