ASP.net MVC3 Выберите внешний ключ в Veiw с помощью DropDownList

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

У меня есть следующие классы моделей:

public class ProjectsTable {
  public int ID {get; set;}
  public String ProjectName {get; set;}
  ...
  public virtual Manager Manager_Id {get; set;}  // Stores foreign key of Manager
}

public class Manager {
  public int ID {get; set;}
  public String ManagerName {get; set;}
  ...
  public virtual ICollection<ProjectsTable> Projects {get; set;}
}

Класс контроллера ProjectsTable содержит следующий метод, дублирующий страницу отображения и редактирования:

private SynthContext db = new SynthContext();
...

// GET: /ProjectsTable/Parameters/5
public ActionResult Parameters(int id) {
  ProjectsTable projectstable = db.ProjectsTable.Find(id);
  ViewBag.Manager_Id = new SelectList(db.Manager, "ID", "ManagerName");
  return View(projectstable);
}

// POST: /ProjectsTable/Parameters/5
public ActionResult Parameters(ProjectsTable projectstable) {
  if(ModelState.IsValid) {
    db.Entry(projectstable).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Parameters");
  }
  ViewBag.Manager_Id = new SelectList(db.Manager, "ID", "ManagerName");
  return View(projectstable);
}

Наконец, Parameters.cshtml содержит следующий код для отображения раскрывающегося списка.

@model Synth.Models.ProjectsTable
...
<fieldset>
...
  <div class="editor-lable">
    @Html.LabelFor(model => model.Manager_ID)
  </div>
  <div class="editor-field">
    @HTML.DropDownList("Manager_ID", String.Empty)
  </div>
  <input type="submit" value="Update">
</fieldset>

Когда я тестирую код, я могу без проблем перейти к /ProjectsTable/Parameters/x; правильно создан раскрывающийся список, содержащий список имен менеджеров. Однако, когда я нажимаю кнопку «Обновить», идентификатор Manager_ID выделяется красным, указывая на то, что изменение не было зарегистрировано. Я могу подтвердить, что изменения не были зарегистрированы, перейдя к /ProjectsTable/list, где я обнаружил, что никакие изменения не вступили в силу.

Я попытался добавить @Html.ValidationMessageFor(Model.Manager_ID), результат всегда "Значение "x" недопустимо", где x - допустимое значение идентификатора (я проверил его по базе данных).

Я просмотрел сгенерированный источник HTML и не вижу там ничего плохого.

У меня есть подозрение, что мне нужно заменить @HTML.DropDownList на @HTML.DropDownListFor, но я не могу понять, какие параметры ему нужны, чтобы он заработал. РЕДАКТИРОВАТЬ. Теперь мне удалось заставить DropDownListFor работать, но проблема не устранена. Связанный с этим вопрос, который поможет мне решить эту проблему, может заключаться в том, как просмотреть данные публикации, отправленные обратно на сервер.

Любая помощь приветствуется.

Всем заранее спасибо...

Чопо


person Chopo87    schedule 25.02.2013    source источник


Ответы (2)


Я думаю, вы запутались, потому что у вас есть свойство модели Manager_Id и объект viewBag Manager_Id. Ваша ошибка modelState относится к свойству модели, а не к каким-либо значениям в раскрывающемся списке, которые привязаны к объекту viewBag. Я предлагаю переименовать ваш ViewBag, чтобы избежать путаницы (или, что еще лучше, вообще не использовать ViewBag), и добавить скрытое поле для свойства модели:

@Html.HiddenFor(m => m.Manager_Id) 

В качестве примечания, исходя из ваших описаний ваших усилий по устранению неполадок выше, я также предлагаю освоить отладку в Visual Studio, установить точки останова и проверить значения. Это сделает вашу жизнь намного проще в долгосрочной перспективе.

person Forty-Two    schedule 25.02.2013
comment
Интересно, что как только я переименую viewbag на m_id и изменю код cshtml на @HTML.DropDownList("m_ID", String.Empty), я больше не получаю никаких ошибок проверки, но теперь мой контроллер просто не регистрирует и не сохраняет то, что я выбираю в DropDownList. Могу ли я на самом деле использовать DropDownList или мне нужно переключиться на DropDownListFor, и если да, то какие параметры мне нужно ввести. - person Chopo87; 25.02.2013
comment
Документация для DropDownListFor: здесь. - person Forty-Two; 25.02.2013
comment
Значения ddl отсутствуют в вашем контроллере, поскольку объект viewBag не является частью модели, которую вы передаете. - person Forty-Two; 25.02.2013
comment
Как правило, вы правы в своем предположении, что вам следует использовать строго типизированный помощник. Просто найдите «Dropdownlistfor». Существуют тысячи практических советов. - person Forty-Two; 25.02.2013
comment
Да, красный, проблема в том, что вот как я интерпретировал это применительно к моему коду: Html.DropDownListFor(model => model.Manager_ID, ViewBag.m_id, String.Empty), но когда я набираю, что VS дает мне следующую ошибку System...ProjectTable has no applicable method named DropDownListFor but appears to have an extension method by that name. Extension methods cannot be dynamically dispatched. Consider casting the dynamic arguments or calling the extension method without the extension method syntax . Я просто не могу расшифровать это сообщение =( - person Chopo87; 25.02.2013
comment
Значения ddl отсутствуют в вашем контроллере, поскольку объект viewBag не является частью модели, которую вы передаете. Я полагаю, именно поэтому вы изначально советовали не использовать ViewBag @Html.HiddenFor(m => m.Manager_Id) - person Chopo87; 25.02.2013
comment
Вам нужно преобразовать объект ViewBag в список выбора для помощника: Html.DropDownListFor(model => model.Manager_ID, ViewBag.m_id as SelectList, String.Empty) - person Forty-Two; 25.02.2013
comment
Спасибо, это позволяет мне использовать DropDownListFor, однако у меня все еще возникает та же проблема: контроллер считает раскрывающийся ответ недействительным. ValidationMessageFor возвращает значение 'x' недопустимо - person Chopo87; 26.02.2013

Итак, я наконец нашел проблему. Это не имело ничего общего с представлением или контроллером. Очевидно, я неправильно написал модель: внешний ключ должен храниться как int?, а также как указатель на рассматриваемую модель.

public class ProjectsTable {
  public int ID {get; set;}
  public String ProjectName {get; set;}
  ...

  public int? ManagerID {get; set;}  // Stores foreign key of Manager
  public virtual Manager Manager // I have no idea if this line does anything
}

public class Manager {
  public int ID {get; set;}
  public String ManagerName {get; set;}
  ...
  public virtual ICollection<ProjectsTable> Projects {get; set;}
}

Хотя это и не обязательно, представление также выигрывает от использования функции:

Html.DropDownListFor(model => model.Manager_ID, ViewBag.Manager_Id as SelectList, String.Empty)

Функция @HTML.DropDownList("ManagerID", String.Empty) тоже работает, но для этого имя объекта ViewBag, передаваемого из контроллера (ManagerID), должно точно совпадать с внешним ключом модели. На мой вкус это запутанно и запутанно. Я предпочитаю строго типизированный подход.

Для полноты я включаю полностью исправленный код:

Контроллер:

private SynthContext db = new SynthContext();
...

// GET: /ProjectsTable/Parameters/5
public ActionResult Parameters(int id) {
  ProjectsTable projectstable = db.ProjectsTable.Find(id);
  // The following line has been amended, but this change is not strictly necessary
  ViewBag.m_id = new SelectList(db.Manager, "ID", "ManagerName", projectstable.ManagerID);
  return View(projectstable);
}

// POST: /ProjectsTable/Parameters/5
public ActionResult Parameters(ProjectsTable projectstable) {
  if(ModelState.IsValid) {
    db.Entry(projectstable).State = EntityState.Modified;
    db.SaveChanges();
    return RedirectToAction("Parameters");
  }
  ViewBag.m_id = new SelectList(db.Manager, "ID", "ManagerName", projectstable.ManagerID);
  return View(projectstable);
}

Вид:

@model Synth.Models.ProjectsTable
...
<fieldset>
...
  <div class="editor-lable">
    @Html.LabelFor(model => model.ManagerID)
  </div>
  <div class="editor-field">
    Html.DropDownListFor(model => model.ManagerID, ViewBag.m_id as SelectList, String.Empty)
    @Html.ValidationMessageFor(model => model.ManagerID)
  </div>
  <input type="submit" value="Update">
</fieldset>
person Chopo87    schedule 26.02.2013