Frage

Ich habe ein vereinfachtes Testszenario, das zum Stellen dieser Frage nützlich ist:Ein Produkt kann viele Komponenten haben, eine Komponente kann zu vielen Produkten gehören.EF hat die Klassen generiert, ich habe sie wie folgt abgespeckt:

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

Die Erstellung einer Komponente erfolgt über die folgenden Controller-Aktionen:

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

und die von der GET-Methode zurückgegebene Ansicht sieht folgendermaßen aus:

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

Daraus ist ersichtlich, dass die Komponentenerstellung auf derselben Seite über die oben genannten Schritte erfolgt Html.Action - Der Code für diese Ansicht folgt:

@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.also das ist es, womit ich zu kämpfen habe:Ich brauche das model Parameter des [HttpPost]back, um ordnungsgemäß ausgefüllt zu werden, d. h.es sollte ein Produkt enthalten, da ich die neue Komponente nicht mit einem Nullprodukt erstellen kann.Um das Produkt zu erhalten, muss ich es über die Produkt-ID nachschlagen.Ich gehe davon aus, dass ich dazu in der Lage sein sollte:

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

oder so etwas, das darauf angewiesen ist model den Ausweis erhalten.Das bedeutet, dass die Ansicht die ID dort platzieren muss, vermutlich in einem versteckten Feld, und wie aus meinem Ansichtscode hervorgeht, habe ich mehrere Versuche unternommen, dies zu füllen, die alle fehlgeschlagen sind.

Normalerweise bevorzuge ich die *For-Methoden, da sie für die Generierung der korrekten Nomenklatur verantwortlich sind.Wenn .Products im Singular (.Product) wäre, könnte ich darauf verweisen als x => x.Product.Id und alles wäre gut, aber da es Plural ist, kann ich es nicht tun x => x.Products.Id also habe ich es versucht x => x.Products.First().Id das den richtigen Wert kompiliert und erzeugt, aber einen Namen erhält Id (was falsch ist, da der Modellbinder denkt, dass es so ist Component.Id und nicht Component.Products[0].Id.

Mein zweiter Versuch war zu lassen HiddenFor iterieren (wie ich es mit tun würde EditorFor):

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

aber das bringt nichts hervor – ich habe gelesen, dass dieser Helfer nicht iteriert.Ich habe es versucht x => x.Products.First() aber das lässt sich nicht einmal kompilieren.Schließlich habe ich beschlossen, auf *For zu verzichten und den Namen selbst zu codieren:

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

und obwohl das richtig aussieht, erkennt das Postback meinen Wert nicht (Products.Count == 0).Ich habe in einem Beitrag gesehen, dass dieses Format aussehen sollte [0].Id aber das funktioniert auch nicht.grr...

Ich schätze, ich könnte es so codieren:

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

und dann meine Controller-Aktion wie folgt neu deklarieren:

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

aber das kommt mir komisch vor.Es ist kaum zu glauben, dass das so schwierig ist.Kann jemand helfen?

  • e

p.s.Ich habe ein Projekt, das ich zum Download zur Verfügung stellen könnte, falls es jemanden interessiert

War es hilfreich?

Lösung

Anstatt diese zu schreiben foreach Schleifen versuchen, Editor-Vorlagen zu verwenden:

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

und innerhalb der entsprechenden Editorvorlage (~/Views/Shared/EditorTemplates/Product.cshtml)

@model Product
@Html.HiddenFor(x => x.Id)
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top