UpdateModel не обновляет модель с помощью ViewModel и свойства из выпадающего списка для

#asp.net-mvc-3 #viewmodel #updatemodel

#asp.net-mvc-3 #viewmodel #updatemodel

Вопрос:

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

Объект, который я пытаюсь обновить, сгенерирован из LinqToSql, и в базе данных у него есть столбец внешнего ключа. В классе LinqToSql это привело к появлению отношения «Содержит». Я могу получить свойство ID, которое представляет столбец в базе данных, а также объект, который он представляет.

         zupanija = new Zupanija();       //object that needs to be updated
        zupanija.Drzava;                 //object that i want to change to make the update
        zupanija.DrzavaID;               //Property linked to object that should change
  

Единственный способ, который я придумал для обновления, — это получить значение из DDLF и использовать его для получения объекта, который я хочу изменить следующим образом:

         [HttpPost]
        public ActionResult Edit(int id, FormCollection collection)
        {
         var zupanija = repo.ZupanijaById(id);
         var drzava = new repoDrzava().DrzavaById(Convert.ToInt32(collection["Zupanija.DrzavaID"]));
         zupanija.Drzava = drzava;
        }
  

Также, когда я пытаюсь обновить поле ID подобным образом, я получаю следующую ошибку:

            zupanija.DrzavaID = Convert.ToInt32(collection["Zupanija.DrzavaID"]);
  

Ошибка: выбрасывает новую System.Data.Linq.Исключение ForeignKeyReferenceAlreadyHasValueException();

Мне кажется, что это очень паршивый способ сделать это, и я пытаюсь заставить UpdateModel работать.

Ответ №1:

Я нашел решение, пока искал что-то еще, в блоге Джо Стивенса:

Использование контроллера UpdateModel при использовании ViewModel

Загвоздка в следующем: когда используется view model, то для правильной привязки свойств необходимо «проинструктировать» помощник UpdateModel, как найти фактический класс, который мы хотим обновить.

Мое решение требовало изменения

  UpdateModel(zupanija); to  UpdateModel(zupanija,"Zupanija");
  

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

     public class ZupanijaFVM
    {
    public IEnumerable<SelectListItem> Drzave { get; private set; }
    public Zupanija Zupanija { get; private set; }
    ...
    }

    // From Controller
    //
    // GET: /Admin/Zupanije/Edit/5
    public ActionResult Edit(int id)
    {
        var zupanija = repo.ZupanijaById(id);
        return zupanija == null ? View("Error") : View(new ZupanijaFVM(repo.ZupanijaById(id)));
    }

    //
    // POST: /Admin/Zupanije/Edit/5

    [HttpPost]
    public ActionResult Edit(int id, FormCollection collection)
    {
        var zupanija = repo.ZupanijaById(id);
        if (TryUpdateModel(zupanija, "Zupanija"))
        {
            repo.Save();
            return RedirectToAction("Details", new { id = zupanija.ZupanijaID });
        }
        return View(new ZupanijaFVM(zupanija));
    }

     //From View:
     @model VozniRed.Areas.Admin.Models.ZupanijeFVM

     <script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
     <script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>
      @using (Html.BeginForm()) 
      {
        @Html.ValidationSummary(true)
        <fieldset>
         <legend>Zupanija</legend>
          @Html.HiddenFor(model => model.Zupanija.ZupanijaID)
         <div class="editor-label">
          @Html.LabelFor(model => model.Zupanija.Naziv)
         </div>
         <div class="editor-field">
          @Html.EditorFor(model => model.Zupanija.Naziv)
          @Html.ValidationMessageFor(model => model.Zupanija.Naziv)
         </div>
         <div class="editor-label">
          @Html.LabelFor(model => model.Zupanija.Drzava)
         </div>
         <div class="editor-field">
          @Html.DropDownListFor(model => model.Zupanija.DrzavaID, Model.Drzave)
          @Html.ValidationMessageFor(model => model.Zupanija.DrzavaID)
         </div>
         <p>
          <input type="submit" value="Save" />
         </p>
       </fieldset>
       }
    <div>
     @Html.ActionLink("Back to List", "Index")
    </div>
  

Ответ №2:

Выпадающий список представлен <select> тегом в HTML-форме. <select> Содержит список <option> тегов, каждый из которых содержит идентификатор и текст. Когда пользователь выбирает опцию и отправляет форму, соответствующий идентификатор этой опции отправляется на сервер. И только идентификатор. Таким образом, все, что вы можете ожидать получить в своем Edit действии POST, — это идентификатор выбранной опции. И все, что UpdateModel делает, это использует параметры запроса, которые отправляются, и преобразует их в строго типизированный объект. Но поскольку все, что опубликовано, — это простой идентификатор, это все, что вы можете получить. С этого момента вам нужно запросить хранилище данных, используя этот идентификатор, если вы хотите получить соответствующую модель. Таким образом, вы не можете получить что-то, чего не существует.