DropDownListFor & Свойства навигации - PullRequest
3 голосов
/ 10 августа 2011

Я столкнулся с проблемой, пытаясь использовать @ Html.DropDownListFor ().

У меня есть модель со свойством навигации:

public class Thing {
  ...
  public virtual Vendor Vendor { get; set; }
}

В контроллере я беру список поставщиков, чтобы выбросить в ViewBag:

public ActionResult Create() {
  ViewBag.Vendors = Vendor.GetVendors(SessionHelper.CurrentUser.Unit_Id);
  return View();
}

Элемент HTML в представлении выглядит следующим образом:

@Html.DropDownListFor(model => model.Vendor, new SelectList(ViewBag.Vendors, "Id", "Name"), "---- Select vendor ----")
@Html.ValidationMessageFor(model => model.Vendor)

Выполняется выпадающий список, и все выглядит нормально, пока я не отправлю форму. Метод HttpPost Create возвращает false на ModelState.IsValid и выдает ошибку модели: Преобразование параметра из типа 'System.String' в тип '... Models.Vendor' завершилось неудачно, поскольку преобразователь типов не может выполнить преобразование между этими типы.

Если я пропускаю страницу, я получаю ошибку сервера: Сведения об исключении: System.ArgumentNullException: значение не может быть нулевым. Название параметра: элементы

После поиска по верхнему и нижнему уровням я не смог найти причину, по которой @ Html.DropDownListFor () неправильно привязывает объект Vendor к свойству навигации.

Любая помощь будет принята с благодарностью.

EDIT: В итоге мне пришлось явно установить атрибуты ForeignKey, чтобы я мог получить прямой доступ к «Vendor_Id», затем я изменил DropDownListFor, указав «Vendor_Id» вместо свойства навигации. Кажется, это работает.

Ответы [ 2 ]

3 голосов
/ 06 октября 2011

Я обнаружил, что лучший способ сделать это заключается в следующем.Измените контроллер для создания SelectListItems.

   public ActionResult Create() {
       ViewBag.Vendors = Vendor.GetVendors(SessionHelper.CurrentUser.Unit_Id)
                               .Select(option => new SelectListItem
                               {
                                  Text = (option == null ? "None" : option.Name),
                                  Value = option.Id.ToString()
                               });
       return View();
    }

Затем измените представление следующим образом:

@Html.DropDownListFor(model => model.Vendor, (IEnumerable<SelectListItem>)ViewBag.Vendors,    "---- Select vendor ----")
@Html.ValidationMessageFor(model => model.Vendor)

Вы должны привести ViewBag.Vendors как (IEnumerable).

Это держит взгляды красивыми и опрятными.Вы также можете переместить код, который получает SelectListItems, в ваш репозиторий и поместить его в метод, называемый что-то вроде GetVendorsList ().

public IEnumerable<SelectListItem> GetVendorsList(int unitId){
    return Vendor.GetVendors(unitId)
                               .Select(option => new SelectListItem
                               {
                                  Text = (option == null ? "None" : option.Name),
                                  Value = option.Id.ToString()
                               });
}

Это будет красиво разделять проблемы и поддерживать ваш контроллер в чистоте.

Удачи

0 голосов
/ 27 мая 2016

Я ответил на аналогичный вопрос в следующем вопросе stackoverflow.Ответ также хорош для этого вопроса.

Проверка свойств навигации в MVC (4) и EF (4)

Этот подход не публикует SelectList в контроллере.Я не думаю, что публикация SelectList в контроллере является хорошей идеей, потому что это означает, что мы заботимся о роли представления в контроллере, что явно не является разделением интересов.

...