2011-05-20 86 views
3

我有一個簡化的測試場景對提問這個問題很有用:一個產品可以有很多組件,一個組件可以屬於許多產品。 EF生成的類,我已經瘦身它們如下:模型活頁夾和隱藏字段

public partial class Product 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Component> Components { get; set; } 
} 
public partial class Component 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public virtual ICollection<Product> Products { get; set; } 
} 

組件的創建是通過這些控制器操作來完成:

public ActionResult Create(int ProductId) 
{ 
    Product p = db.Products.Find(ProductId); 
    Component c = new Component(); 
    c.Products.Add(p); 
    return PartialView(c); 
} 

[HttpPost] 
public ActionResult Create(Component model) 
{ 
    db.Components.Add(model); 
    db.SaveChanges(); 
} 

並通過GET方法返回的觀點是這樣的:

@model Test.Models.Product 

<fieldset> 
    <legend>Product</legend> 
    <div class="display-label">Name</div> 
    <div class="display-field">@Model.Name</div> 
</fieldset> 

@Html.Action("Create", "Component", new {ProductId = Model.Id}) 
<p> 
    @Html.ActionLink("Edit", "Edit", new { id=Model.Id }) | 
    @Html.ActionLink("Back to List", "Index") 
</p> 

從中可以看出,該組件創建是在同一頁上通過上述處理Html.Action - 該視圖的代碼如下:

@model Test.Models.Component 
@using Test.Models 

<script type="text/javascript"> 
    function Success() { 
     alert('ok'); 
    } 
    function Failure() { 
     alert('err'); 
    } 
</script> 
@using (Ajax.BeginForm("Create", "Component", new AjaxOptions 
{ 
    HttpMethod = "Post", 
    OnSuccess = "Success", 
    OnFailure = "Failure" 
})) 
{ 
    <fieldset> 
     <legend>Components</legend> 

     <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> 
     @Html.HiddenFor(x => x.Products.First().Id) 
     @Html.HiddenFor(x => x.Products) 
     @foreach (Product p in Model.Products) 
     { 
      @Html.Hidden("Products[0].Id", p.Id) 
     } 
     @foreach (Product p in Model.Products) 
     { 
      @Html.Hidden("[0].Id", p.Id) 
     } 
    </fieldset> 
    <input type="submit" value="go" /> 
} 

好的。所以這就是我所苦苦掙扎的:我需要[HttpPost]的model參數得到適當的填充,即它應該包含一個Product,因爲我無法用空產品創建新組件。要獲得產品,我需要通過產品的ID來查找它。我希望我能夠做到:

model.Products.Add(db.Products.Find(model.Products.First().Id)); 

或一些這樣的事情,這依賴於model接收的ID。這意味着視圖必須將id放置在那裏,大概在隱藏的字段中,並且從我的視圖代碼中可以看出,我已經做了幾次嘗試來填充它,所有這些都失敗了。

通常我更喜歡* For方法,因爲它們負責生成正確的命名。如果.Products是單數(.Product),我可以參考它作爲x => x.Product.Id和一切都會好,但由於它是複數,我不能做x => x.Products.Id所以我試圖x => x.Products.First().Id編譯和產生正確的價值,但得到名稱Id是錯誤的,因爲模型綁定認爲這是Component.Id而不是Component.Products[0].Id

我的第二次嘗試,讓HiddenFor迭代(就像我會EditorFor):

@Html.HiddenFor(x => x.Products) 

但產生什麼 - 我讀過,這個幫手不會迭代,我試過x => x.Products.First()但這甚至沒有編譯。最後,我決定放棄*對於和惡意代碼的名稱自己:

@foreach (Product p in Model.Products) 
{ 
    @Html.Hidden("Products[0].Id", p.Id) 

,雖然看起來正確,回傳並沒有看到我的價值(Products.Count == 0)。我在一些帖子中看到,格式應該看起來像[0].Id,但這也不起作用。 GRR ...

我猜我可能這樣的代碼是:

@Html.Hidden("ProductId", p.Id) 

,然後再次聲明我的控制器操作是這樣的:

[HttpPost] ActionResult Create(Component model, int ProductId) 

但似乎eecky。很難相信這是如此困難。誰能幫忙?

  • Ë

附:我有一個項目,我可以讓提供下載,如果有人關心

回答

13

而不是寫那些foreach循環使用編輯模板嘗試:

<fieldset> 
    <legend>Components</legend> 

    <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> 

    @Html.EditorFor(x => x.Products) 
</fieldset> 

和相應的編輯模板(~/Views/Shared/EditorTemplates/Product.cshtml

@model Product 
@Html.HiddenFor(x => x.Id) 
+0

內ohhhhh ........那真是太棒了。如果我有一大堆學分可以讓你立刻得到它們。笑...我必須如此密集,解決方案不會發生在我身上。謝謝一堆! – ekkis 2011-05-20 16:07:47

+1

我心中留下的一個問題是:爲什麼我的第一個循環沒有工作?它生成了''這看起來是正確的,但後端沒有拿起它。 .EditorFor()方法生成相同的輸出,不同之處在於它添加了數據驗證標記屬性... – ekkis 2011-05-20 16:16:28