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

わかった。これが私が苦労していることです。model適切に入力するには、[HttpPost] backのパラメーターが必要です。つまり、nullの製品で新しいコンポーネントを作成できないため、製品が含まれている必要があります。製品を入手するには、製品の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().IdIdComponent.IdComponent.Products[0].Id

私の2番目の試みは、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が、それも機能しません。grr..。

私はそれを次のようにコーディングできると思います:

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

次に、コントローラーのアクションを次のように再宣言します。

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

しかし、それは厄介なようです。これがとても難しいとは信じがたいです。誰か助けてもらえますか?

  • e

ps誰かが気にかけたら、ダウンロードできるようにするプロジェクトがあります

4

1 に答える 1

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)
于 2011-05-20T07:24:09.170 に答える