2011-12-20 72 views
10

TL; DR:在我的ASP.NET MVC3應用程序中,應該如何實現一個視圖,該視圖允許我同時編輯「父」實體的詳細信息「兒童」實體列表?綁定兒童的可編輯列表

更新:我接受@torm's answer,因爲他提供a link給出一些解釋,爲什麼我目前的解決方案可能是因爲它得到不錯的。 但是,我們很樂意聽取其他人是否有其他選擇!

我一直在尋找和閱讀(到目前爲止,參見底部的'參考'部分底部的一些發現)。 不過,我仍然覺得迄今爲止我找到的解決方案有點「臭」。我想知道你們中的任何一個人是否有更優雅的回答或建議(或者可以解釋爲什麼這可能「儘可能好」)。 提前致謝!

所以,這裏的設置:

型號:

public class Wishlist 
{ 
    public Wishlist() { Wishitems = new List<Wishitem>(); } 

    public long WishListId { get; set; } 
    public string Name { get; set; } 
    public string Description { get; set; } 

    public virtual ICollection<Wishitem> Wishitems { get; set; } 
} 
public class Wishitem 
{ 
    public long WishitemId { get; set; } 
    public string Name { get; set; } 
    public int Quantity { get; set; } 
} 

控制器:

public class WishlistsController : Controller 
{ 
    private SandboxDbContext db = new SandboxDbContext(); 
    /* ... */ 
    public ActionResult Edit(long id) 
    { 
     Wishlist wishlist = db.Wishlists.Find(id); 
     return View(wishlist); 
    } 

    [HttpPost] 
    public ActionResult Edit(Wishlist wishlist) 
    //OR (see below): Edit(Wishlist wishlist, ICollection<Wishitem> wishitems) 
    { 
     if (ModelState.IsValid) 
     { 
      db.Entry(wishlist).State = EntityState.Modified; 
      db.SaveChanges(); 
      return RedirectToAction("Index"); 
     } 
     return View(wishlist); 
    } 
    /* ... */ 
} 

觀:瀏覽次數\收藏\ Edit.cshtml

@model Sandbox.Models.Wishlist 
<h2>Edit</h2> 
<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>Wishlist</legend> 
     @Html.HiddenFor(model => model.WishListId) 
     <div class="editor-label">@Html.LabelFor(model => model.Name)</div> 
     <div class="editor-field"> 
      @Html.EditorFor(model => model.Name) 
      @Html.ValidationMessageFor(model => model.Name) 
     </div> 
    </fieldset> 
    <table> 
     <tr> 
      <th> 
       Quantity 
      </th> 
      <th> 
       Name 
      </th> 
     </tr> 
     @for (var itemIndex = 0; itemIndex < Model.Wishitems.Count; itemIndex++) 
    { 
      @Html.EditorFor(item => Model.Wishitems.ToList()[itemIndex]) 
    } 
    </table> 
    <p> 
     <input type="submit" value="Save" /> 
    </p> 
} 

編輯器模板:視圖\共享\編輯器模板\ Wishitem.cshtml

@model Sandbox.Models.Wishitem 
<tr> 
    <td> 
     @Html.HiddenFor(item=>item.WishitemId) 
     @Html.TextBoxFor(item => item.Quantity) 
     @Html.ValidationMessageFor(item => item.Quantity) 
    </td> 
    <td> 
     @Html.TextBoxFor(item => item.Name) 
     @Html.ValidationMessageFor(item => item.Name) 
    </td> 
</tr> 

這是怎麼回事?

上面的設置生成標準輸入元素的網頁爲「父」的收藏模式:

<input class="text-box single-line" id="Name" name="Name" type="text" value="MyWishlist" /> 

對於「孩子」在表中Wishitems,我們獲得索引輸入元素:

<input data-val="true" data-val-number="The field Quantity must be a number." data-val-required="The Quantity field is required." name="[0].Quantity" type="text" value="42" /> 
<input name="[0].Name" type="text" value="Unicorns" /> 

這會導致Wishlist wishlist參數以空的.Wishitems屬性回傳。

POST處理程序([HttpPost] public ActionResult Edit(Wishlist wishlist, ICollection<Wishitem> wishitems))的另一個簽名仍爲空wishlist.Wishitems,但允許我訪問(可能已修改的)wishitems

在這第二種情況下,我可以做一些自定義綁定。例如(不是最優雅的代碼我已經看到了我的職業生涯):

[HttpPost] 
public ActionResult Edit(Wishlist editedList, ICollection<Wishitem> editedItems) 
{ 
    var wishlist = db.Wishlists.Find(editedList.WishListId); 
    if (wishlist == null) { return HttpNotFound(); } 

    if (ModelState.IsValid) 
    { 
     UpdateModel(wishlist); 

     foreach (var editedItem in editedItems) 
     { 
      var wishitem = wishlist.Wishitems.Where(wi => wi.WishitemId == editedItem.WishitemId).Single(); 
      if (wishitem != null) 
      { 
       wishitem.Name = editedItem.Name; 
       wishitem.Quantity = editedItem.Quantity; 
      } 
     } 
     db.SaveChanges(); 
     return View(wishlist); 
    } 
    else 
    { 
     editedList.Wishitems = editedItems; 
     return View(editedList); 
    } 
} 

我的收藏

我希望能有讓我得到在一個單一的結構化對象的所有已發佈數據的方式如:

[HttpPost] 
public ActionResult Edit(Wishlist wishlist) { /* ...Save the wishlist... */ } 

隨着wishlist.Wishitems充滿了(可能已修改)項目

還是比較埃爾例如,如果我的控制器必須單獨接收它們,我可以處理數據的合併。喜歡的東西

[HttpPost] 
public ActionResult Edit(Wishlist editedList, ICollection<Wishitem> editedItems) 
{ 
    var wishlist = db.Wishlists.Find(editedList.WishListId); 
    if (wishlist == null) { return HttpNotFound(); } 

    if (ModelState.IsValid) 
    { 
     UpdateModel(wishlist); 
     /* and now wishlist.Wishitems has been updated with the data from the Form (aka: editedItems) */ 
     db.SaveChanges(); 
     return View(wishlist); 
    } 
    /* ...Etc etc... */ 
} 

提示,技巧,想法?

注:

  • 這是一個沙盒的例子。我正在處理的實際應用程序非常不同,與在Sandbox中公開的域無關。
  • 我沒有在示例中使用'ViewModels',因爲 - 遠 - 他們似乎不是答案的一部分。如果他們有必要,我肯定會介紹他們(並且在我正在研究的真實應用程序中,我們已經在使用它們)。
  • 同樣,在本例中,存儲庫被簡單的SandboxDbContext類抽象出來,但可能會被實際應用程序中的通用存儲庫和工作單元模式所取代。
  • 沙盒應用程序是使用內置:
    • 的Visual Web Developer 2010速成
      • 修復微軟的Visual Web Developer 2010速成 - ENU(KB2547352)
      • 修復微軟的Visual Web Developer 2010速成 - ENU(KB2548139)
      • 微軟的Visual Web Developer 2010速成 - ENU的Service Pack 1(KB983509)
    • 的.NET Framework 4.0.30319 SP1Rel
    • ASP.NET MVC3
      • 剃刀語法觀
      • 代碼優先方法
    • 實體框架4.2.0.0
  • 沙盒構建目標。NET Framework 4的

參考文獻:

  • "Getting Started with ASP.NET MVC3" 涵蓋了基礎知識,但不與模型關係

  • "Getting Started with EF using MVC" 的-ASP淨MVC應用程序 特別處理Part 6顯示瞭如何處理模型之間的一些關係。 但是,本教程對其POST處理程序使用FormCollection參數,而不是自動模型綁定。 換句話說: [HttpPost]公開的ActionResult編輯(INT ID,的FormCollection的FormCollection) 而不是沿着 [HttpPost]公開的ActionResult編輯(InstructorAndCoursesViewModel視圖模型)的線的東西 此外,對於一個給定的講師相關課程列表(在UI中)被表示爲一組具有相同名稱的複選框(導致POST處理程序的參數爲string[]),這與我所看到的並不完全相同。

  • "Editing a variable length list, ASP.NET MVC2-style" 基於MVC2(所以我想知道它是否仍然描述我們有MVC3的最佳選擇)。 不可否認,我還沒有處理從列表中插入和/或刪除兒童模型。 此外,該解決方案:

    • 依賴於自定義代碼(BeginCollectionItem) - 這是,如果它是必要的罰款(但它仍然是必要的,MVC3?)
    • 處理列表作爲一個獨立的採集,而不是包裝模型的屬性 - 換言之,周圍有「GiftsSet」模型(相當於我的示例中的父母Wishlist模型),儘管我不知道引入明確的父模型是否使此解決方案失效。
  • "ASP.NET Wire Format for Model Binding to Arrays, Lists, Collections, Dictionaries" 斯科特Hanselman的職位是被引用最多的基準兒子一個在MVC應用程序綁定到列表中的主題。但是,他只是簡單地描述了框架採用的命名約定,並用於生成與您的操作方法匹配的對象(請注意文章沒有生成頁面然後將數據提交到所描述操作之一的示例)。 這是很好的信息,如果我們必須自己生成HTML。我們必須嗎?

  • "Model Binding To A List" 菲爾哈克的另一個頂級參考。它具有與上述Hansleman帖子相同的信息,但也向我們展示了我們可以在循環(for (int i = 0; i < 3; i++) { Html.TextBoxFor(m => m[i].Title) })或編輯器模板(Html.EditorFor(m=>m[i]))中使用HtmlHelpers。 但是,使用這種方法,由編輯器模板生成的HTML不會包含任何特定的前綴(例如:輸入元素的名稱和ID將採用[index].FieldName的形式,如:[0].Quantity[1].Name)。在這個例子中,這可能是也可能不是關鍵,但在我的實際應用程序中可能會出現問題,其中不同的「平行」子項目列表可能出現在同一個視圖中。

+0

需要將frame你的問題,可以輕鬆讀取 – user1006544 2011-12-20 07:33:20

回答

1

你可能要檢查這個鏈接http://www.codetuning.net/blog/post/Binding-Model-Graphs-with-ASPNETMVC.aspx我有類似的問題,上面讓我明白

+0

感謝您的鏈接。所以..我只需要咬下子彈並寫下我自己的自定義聯編程序?那麼,至少現在我知道爲什麼默認聯編程序是不夠的,我可以留意來自MS的任何更新。謝謝你的提示;在接受答案之前,我會稍微等一下(希望看看是否有其他人建議替代方案,並且我想在今晚在家中的沙箱應用中試用它)。 – FOR 2011-12-20 13:16:32

+0

是的,請等待,我也對解決方案感興趣。到目前爲止,我已經迭代了我的對象的集合,並使用jQuery $ .post逐個提交每個子實體,但它有一些限制 – torm 2011-12-20 13:46:32

+0

鏈接已損壞:( – TWilly 2016-07-26 14:42:16