2011-05-20 85 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