Правильный способ редактирования объекта в MVC 3 с помощью Entity Framework с использованием подхода Data Model First? - PullRequest
0 голосов
/ 12 января 2012

В большинстве примеров, которые я вижу сейчас, либо используется подход Code First, либо используется более старая версия MVC и Entity Framework.

Предположим, у меня есть фильм для обновления, и я попадаю в представление редактированияв методе Edit с глаголом Post, как правильно обновить фильм?Первый метод редактирования, приведенный ниже, возвращает меня к представлению редактирования с заполненными значениями Movie, а второй - тот, который я хочу использовать для обновления, я пробовал кое-что, но данные не обновляются.

 public ActionResult Edit(int id)
        {
            var movie = (from m in _db.Movies1
                         where m.Id == id
                         select m).First();

            return View(movie);
        }

    [HttpPost]
    public ActionResult Edit(Movie movie)
    {
        try
        {
            // TODO: Add update logic here

           //What do I need to call to update the entity?

            _db.SaveChanges();
            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

Ответы [ 2 ]

4 голосов
/ 12 января 2012

Предполагая, что _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, но не на свойства навигации.

0 голосов
/ 12 января 2012

Ваш второй метод редактирования должен выглядеть примерно так:

[HttpPost]
public ActionResult Edit(int id, FormCollection collection)
{
    var movie = (from m in _db.Movies1
                     where m.Id == id
                     select m).First();
     if (TryUpdateModel(movie))
        {
            _db.SaveChanges();
            return (RedirectToAction("Index"));
        }

        return View(movie);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...