MVC 3 EF 4.1 POCOs шаблон ViewModel контроллер со строительными лесами == путаница!

#asp.net-mvc-3 #entity-framework-4 #razor #viewmodel #poco

#asp.net-mvc-3 #entity-framework-4 #бритва #viewmodel #poco

Вопрос:

Я [наконец-то!] решение MVC (версии 3) после многих лет ASP.NET разработка форм. У меня большой опыт работы с n-уровневой архитектурой приложений, и я пытаюсь подойти к этому новому проекту должным образом, с четким разделением задач и т.д.

Что я сделал, так это начал с кода -сначала создав свои POCOs. На основе этого фреймворка была создана моя база данных.

Затем я реализовал шаблон репозитория, поместив все мои методы EF query и CRUD в класс репозитория для каждого из моих классов POCO в сборке моих моделей. Таким образом, моим контроллерам не нужно ничего знать о том, как я получаю доступ к своим данным через EF. Отлично.

Наконец, я создал несколько классов ViewModel в моей сборке Models. Мое намерение состоит в том, чтобы для определенных действий (таких как создание и редактирование) я ссылался на свои классы ViewModel из представлений RAZOR, а не на свои классы POCO. Таким образом, у меня может быть свой класс POCO, а также список выбора для заполнения выпадающего списка в моей ViewModel. Оба заполнены ссылками на связанные классы репозитория, которые вызываются из моих действий контроллера. Я думаю, что теперь я в ударе:

 class MyObject 
{
    public int ID {get;set}

    [Required]
    [StringLength(512)]     
    public string Name {get;set;}

}

class MyViewModel // ViewModel for a specific view 
{
    public MyObject MyModel {get;set;}        // the model that is being edited 

    // other data the view might need, set by the controller 
    public string SomeMessage { get; set; }
    public List<SomeObject> SomeObjects {get;set;} /// e.g. for a drop-down list

    // My constructor below that populates the "SomeObjects" list, and accepts the
    // "MyObject" class as a parameter in order to set the "MyModel" property above...
    // ..........

}
  

Проблема…

Прежде чем я начал использовать свои классы ViewModel из действий создания и редактирования моего контроллера, я передал класс POCO напрямую. Все работало нормально, когда я нажал кнопку сохранения из моей формы редактирования в моем представлении:

Старый код:

 [HttpPost]
public ActionResult Edit(MyObject mine) 
{
    if (ModelState.IsValid) 
    {
        myRepository.Update(mine);
        myRepository.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(mine);
}
  

Когда я нажимал сохранить, мой класс POCO (MyObject) возвращался, автоматически заполнялся значениями из формы, он успешно сохранялся, и жизнь была прекрасна.

Когда я переключился на передачу моей ViewModel (MyViewModel), все развалилось.

Я смог ссылаться на свою ViewModel (MyViewModel), установив ссылку @model в верхней части моего вида редактирования. Затем я смог заполнить поля моей формы из моего класса POCO (MyObject), который является частью ViewModel. Я даже смог заполнить выпадающий список из коллекции SomeObjects в ViewModel и предварительно выбрать правильный из моего класса MyObject, который я редактировал. Все казалось прекрасным, ПОКА

Когда я нажал кнопку сохранения и был вызван результат редактирования ActionResult моего контроллера (POST action), класс MyObject, который передается в ActionResult (public ActionResult Edit(MyObject mine)), был равен нулю.

Затем я попытался изменить переданный объект на мой ViewModel (public ActionResult Edit(MyViewModel myVM)), в котором класс MyObject, на который ссылается MyObject (MyModel), равен null.

Чего мне не хватает?

Я знаю, что это должно быть что-то настолько невероятно простое, что это бросается мне в глаза, и я не могу этого видеть!

Ответ №1:

Посмотрите на FormCollection, имена ключей должны соответствовать свойствам класса, который вы хотите заполнить. Вот как работает привязка модели MVC по умолчанию.

Комментарии:

1. Дело в том, что я не менял названия ключей в FormCollection. Это работало, когда я изначально ссылался только на свой класс POCO в объявлении @model представления. Когда я изменил объявление @model на свой класс ViewModel, именно тогда все перестало работать. Я знаю, что здесь мне не хватает чего-то простого.

2. Я только что увидел комментарий о конструкторе MyViewModel. Modelbinder ожидает конструктор без параметров.

Ответ №2:

Wim,

Большое спасибо за вашу помощь. У меня действительно был конструктор без параметров, я просто опустил его из примера.

Я действительно отследил проблему. Справедливости ради, код, который я ввел, не был фактическим кодом, поскольку у меня его не было передо мной, когда я публиковал это. Проблема заключалась в том, что ссылка на класс моей модели объекта в моей ViewModel фактически имела свой набор доступа как закрытый:

 public MyObject MyModel {get;private set;}
  

Это помешало modelbinder заполнить это свойство при повторной публикации во время метода сохранения контроллера.

Что мне осталось сделать сейчас, так это перенести мою логику проверки из моего EF POCO в мою ViewModel, как, кажется, рекомендуемое действие в шаблоне такого типа.

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

Комментарии:

1. Здорово, что вы решили свою проблему! Задайте свой ответ в качестве решения, чтобы другие могли видеть, что на вопрос дан ответ.