2012-06-23 3 views
3

Я пишу свое первое приложение MVC3, которое является простым приложением отслеживания заказов. Я хотел бы отредактировать заказ и детали одновременно. Когда я редактирую заказ, ActionResult для Edit возвращает порядок и связанную строку (я также использую EF).Сохранение нескольких объектов из представления MVC

public ActionResult Edit(int id) 
    {    
     // Get the order with the order lines 
     var orderWithLines = from o in db.Orders.Include("OrderLines") 
           where o.ID == id 
           select o; 

     // Not sure if this is the best way to do this. 
     // Need to find a way to cast to "Order" type 
     List<Order> orderList = orderWithLines.ToList(); 
     Order order = orderList[0]; 

     // Use ViewData rather than passing in the object in the View() method. 
     ViewData.Model = order; 
     return View();    
    } 

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

@model OrderTracker.Models.Order 

@{ 
    ViewBag.Title = "Edit"; 
} 

<h2>Edit</h2> 

@using (Html.BeginForm()) 
{ 
    <fieldset> 
     <legend>Order</legend> 

     @Html.HiddenFor(model => model.ID) 
     @Html.HiddenFor(model => model.UserId) 

     <div> 
      @Html.LabelFor(model => model.OrderDate) 
     </div> 
     <div> 
      @Html.EditorFor(model => model.OrderDate) 
     </div> 
     <div> 
      @Html.LabelFor(model => model.Description) 
     </div> 
     <div> 
      @Html.EditorFor(model => model.Description) 
     </div>     

     <table> 
      <tr> 
       <th> 
        Description 
       </th> 
       <th> 
        Quantity 
       </th> 
       <th> 
        Weight 
       </th> 
       <th> 
        Price 
       </th> 
       <th></th> 
      </tr> 
     @foreach (var line in Model.OrderLines) 
     { 
      <tr> 
       <td> 
        @Html.EditorFor(modelItem => line.Description) 
       </td> 
       <td> 
        @Html.EditorFor(modelItem => line.Quantity) 
       </td> 
       <td> 
        @Html.EditorFor(modelItem => line.Weight) 
       </td> 
       <td> 
        @Html.EditorFor(modelItem => line.Price) 
       </td> 
      </tr> 
     } 
     </table> 


     <p> 
      <input type="submit" value="Save" /> 
     </p> 

    </fieldset>  
} 

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

Спасибо.

ответ

7

Вопрос, который вы столкнулись связано с именами порожденных ICollection<T> управления. Вот detailed discussion by Phil Haack и решение от него (в терминах метода расширения @Html; скачать образец проекта по ссылке, указанной в конце его сообщения в блоге). Это сообщение предназначено для MVC/MVC2; однако он по-прежнему применим к MVC3.

В качестве альтернативы, если вы не хотите следить за хаком, вы можете выбрать EditorTemplate для вашей модели OrderLine.

Вот шаги.

1) Создать шаблон редактора в разделе (Views ->Shared -> EditorTemplates -> OrderLine.cshtml) Важно, чтобы создать папку с именем EditorTemplates под Shared, и имя шаблона должно быть таким же, как EntityModel, для которого вы хотите создать Templete; отсюда название OrderLine.cshtml)

enter image description here

2) Код для OrderLine.cshtml

@model OrderTracker.Models.OrderLine 
@{ 
    Layout = null; 
} 

<!DOCTYPE html> 
@Html.HiddenFor(modelItem => Model.id) 
<tr> 
<td> 
    @Html.EditorFor(modelItem => Model.Description) 
</td> 
<td> 
    @Html.EditorFor(modelItem => Model.Quantity) 
</td> 
<td> 
    @Html.EditorFor(modelItem => Model.Weight) 
</td> 
<td> 
    @Html.EditorFor(modelItem => Model.Price) 
</td> 
</tr> 

3) Редактировать свой вид с помощью этого кода (обратите внимание, что я использовал EditorFor для коллекции OrderLines)

@model OrderTracker.Models.Order 

@{ 
    ViewBag.Title = "Edit"; 
} 

<h2>Edit</h2> 

@using (Html.BeginForm()) 
{ 
    <fieldset> 
     <legend>Order</legend> 

     @Html.HiddenFor(model => model.ID) 
     @Html.HiddenFor(model => model.UserId) 

     <div> 
      @Html.LabelFor(model => model.OrderDate) 
     </div> 
     <div> 
      @Html.EditorFor(model => model.OrderDate) 
     </div> 
     <div> 
      @Html.LabelFor(model => model.Description) 
     </div> 
     <div> 
      @Html.EditorFor(model => model.Description) 
     </div>      
     <div> 
     <table> 
      <tr> 
       <th> 
        Description 
       </th> 
       <th> 
        Quantity 
       </th> 
       <th> 
        Weight 
       </th> 
       <th> 
        Price 
       </th> 
      </tr> 
      @Html.EditorFor(model => model.OrderLines) 
      </table> 
     </div> 
     <p> 
      <input type="submit" value="Save" /> 
     </p> 

    </fieldset>  
} 

4) Теперь на пост обратно вы увидите значения

enter image description here

+0

не работал в ASP MVC 5, любые указатели, пожалуйста, отправляйте пакет Ienumerable transformer

+0

@transformer отлично работает в MVC5. Что не для вас? Модель «Заказ» будет иметь список предметов «OrderLine». Обратите особое внимание на пункты 1 и 3 в моем ответе. У вас есть образец кода в реестре github? –

0

Используя MVC, он должен быть достаточно прочным, поскольку каркас предназначен для превращения формы в модель.

[HttpGet] 
public ActionResult Edit(int id) 
{ 
    // (you can probably rewrite this using a lambda 
    var orderWithLines = from o in db.Orders.Include("OrderLines") 
         select o; 

    // Use ViewData rather than passing in the object in the View() method. 
    ViewData.Model = orderWithLines.FirstOrDefault(x => x.ID = id); 
    return View(); 
} 

[HttpPost] 
public ActionResult Edit(OrderTracker.Models.Order model) 
{ 
    if (ModelState.IsValid) 
    { 
     // call the service layer/repository/db to persist the object graph 
     _service.Save(model); // this assumes your view models are the same as your domain 
    } 
} 
0

Проблема с вашим Еогеасп, если вы посмотрите на сырье HTML, что она производит не будет генерации уникальных идентификаторов для каждой из линий порядка и, следовательно, не сможет связать модель, когда форма отправлено назад.

Измените foreach на цикл for, а затем укажите каждую строку заказа, используя индекс. Это позволит создавать уникальные идентификаторы в форме и позволяет привязать их к модели, когда она будет отправлена ​​обратно.

например.

@for (var counter = 0; counter < Model.OrderLines.Count(); counter++) 

    { 
     <tr> 
      <td> 
       @Html.EditorFor(modelItem => Model.OrderLines[counter].Description) 
      </td> 
      <td> 
       @Html.EditorFor(modelItem => Model.OrderLines[counter].Quantity) 
      </td> 
      <td> 
       @Html.EditorFor(modelItem => Model.OrderLines[counter].Weight) 
      </td> 
      <td> 
       @Html.EditorFor(modelItem => Model.OrderLines[counter].Price) 
      </td> 
     </tr> 
    } 
    </table> 
+0

Я пробовал это и получил исключение, заявив, что Я не могу использовать индекс с коллекцией. Я просмотрел созданный HTML и вижу, что для каждой строки есть одинаковые идентификаторы HTML-элементов (не уверен, что это проблема). Таким образом, похоже, мне нужен другой способ привязки элементов представления к контроллеру. Я не понимаю, как представление привязывается к контроллеру. Соответствует ли представление и контроллер идентификатору HTML-элемента? Любые ссылки на четкое определение будут оценены. – user1476207

+0

Извините, должно быть, были OrderLines not Orderlines. Когда вы отправляете обратно на контроллер, он будет использовать Id для привязки модели - например, элемент с идентификатором «OrderLines_2__Description» - это поле описания для второй OrderLine. –

Смежные вопросы