模型活页夹隐藏字段

发布于 2024-11-08 03:47:37 字数 3830 浏览 5 评论 0原文

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

但是没有产生任何结果 - 我读到这个助手没有迭代,但它甚至没有编译。 *For 并自己编写名称:

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

虽然看起来正确,但回发看不到我的值(Products.Count == 0),我在一些帖子中看到该格式应类似于 < code>[0].Id 但这也不起作用。

我想我可以这样编码:

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

然后像这样重新声明我的控制器操作:

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

但这看起来令人难以置信。这太难了。有人可以帮忙吗?

  • 如果有人关心的话

,我可以提供一个项目。

I have a simplified test scenario useful for asking this question: A Product can have many Components, a Component can belong to many Products. EF generated the classes, I've slimmed them as follows:

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

The creation of a component is accomplished via these controller actions:

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();
}

and the view returned by the GET method looks like this:

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

From which can be seen that the component creation is handled on the same page via the above Html.Action - the code for that view follows:

@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" />
}

ok. so this is what I'm struggling with: I need the model parameter of the [HttpPost]back to get properly populated i.e. it should contain a Product, since I can't create the new component with a null product. To get the product I need to look it up via the product's id. I expect I should be able to do:

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

or some such thing, which relies on model receiving the id. This means the view has to place the id there, presumably in a hidden field, and as can be seen from my view code, I've made several attempts at populating this, all of which have failed.

Normally I prefer the *For methods since they become responsible for generating correct nomenclature. If .Products were singular (.Product), I could reference it as x => x.Product.Id and everything would be fine, but since it's plural, I can't do x => x.Products.Id so I tried x => x.Products.First().Id which compiles and produces the right value but gets name Id (which is wrong since the model binder thinks it's Component.Id and not Component.Products[0].Id.

My second attempt was to let HiddenFor iterate (like I would with EditorFor):

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

but that produces nothing - I've read that this helper doesn't iterate. I tried x => x.Products.First() but that doesn't even compile. Finally, I decided to abandon the *For and code the name myself:

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

and though that looks right, the postback doesn't see my value (Products.Count == 0). I saw in some posting that format should look like [0].Id but that doesn't work either. grr...

I gather I could code it like this:

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

and then redeclare my controller action like this:

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

but that seems eecky. it's hard to believe this is so difficult. can anyone help?

  • e

p.s. I have a project I could make available for download if anyone cares

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

美人骨 2024-11-15 03:47:37

不要编写这些 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)

Instead of writing those foreach loops try using editor templates:

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

and inside the corresponding editor template (~/Views/Shared/EditorTemplates/Product.cshtml)

@model Product
@Html.HiddenFor(x => x.Id)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文