我有一个简化的测试场景,对于提出这个问题很有用:一个产品可以有多个组件,一个组件可以属于多个产品。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" />
}

好的。所以这就是我正在努力解决的问题:我需要 model [HttpPost]back 的参数以正确填充,即它应该包含一个产品,因为我无法使用空产品创建新组件。要获取产品,我需要通过产品 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() 但这甚至无法编译。最后,我决定放弃 *For 并自己编写名称:

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

尽管这看起来是正确的,但回发并没有看到我的价值(Products.Count == 0)。我在一些帖子中看到格式应该是这样的 [0].Id 但这也行不通。呃……

我想我可以这样编码:

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

然后重新声明我的控制器操作,如下所示:

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

但这看起来很令人讨厌。很难相信这是如此困难。有人可以帮忙吗?

  • e

附注我有一个项目,如果有人关心的话,我可以提供下载

有帮助吗?

解决方案

而不是写那些 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)
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top