Domanda

Ho uno scenario di test semplificato utile per porre questa domanda:Un Prodotto può avere molti Componenti, un Componente può appartenere a molti Prodotti.EF ha generato le classi, le ho snellite come segue:

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

La creazione di un componente viene eseguita tramite queste azioni del controller:

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

e la vista restituita dal metodo GET è simile alla seguente:

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

Da cui si può vedere che la creazione del componente viene gestita nella stessa pagina tramite quanto sopra Html.Action - il codice per quella vista segue:

@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.quindi questo è ciò con cui sto lottando:ho bisogno di model parametro del [HttpPost]back per essere popolato correttamente, ad es.dovrebbe contenere un prodotto, poiché non posso creare il nuovo componente con un prodotto nullo.Per ottenere il prodotto devo cercarlo tramite l'ID del prodotto.Mi aspetto che dovrei essere in grado di fare:

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

o qualcosa del genere, su cui si basa model ricevendo l'ID.Ciò significa che la vista deve posizionare l'id lì, presumibilmente in un campo nascosto, e come si può vedere dal codice della mia vista, ho fatto diversi tentativi per popolarlo, tutti falliti.

Normalmente preferisco i metodi *For poiché diventano responsabili della generazione della nomenclatura corretta.Se .Products fosse singolare (.Product), potrei fare riferimento ad esso come x => x.Product.Id e andrebbe tutto bene, ma visto che è plurale, non posso farlo x => x.Products.Id quindi ho provato x => x.Products.First().Id che compila e produce il valore corretto ma ottiene il nome Id (il che è sbagliato poiché il raccoglitore del modello pensa che sia Component.Id e non Component.Products[0].Id.

Il mio secondo tentativo è stato quello di lasciare HiddenFor iterare (come farei con EditorFor):

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

ma ciò non produce nulla: ho letto che questo aiutante non esegue iterazioni.ho provato x => x.Products.First() ma questo non viene nemmeno compilato.Alla fine, ho deciso di abbandonare *For e codificare io stesso il nome:

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

e sebbene sembri corretto, il postback non vede il mio valore (Products.Count == 0).Ho visto in alcuni post che il formato dovrebbe assomigliare [0].Id ma non funziona neanche questo.gr...

Immagino che potrei codificarlo in questo modo:

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

e quindi dichiarare nuovamente l'azione del controller in questo modo:

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

ma sembra inquietante.è difficile credere che sia così difficile.qualcuno può aiutare?

  • e

p.s.Ho un progetto che potrei rendere disponibile per il download se a qualcuno interessa

È stato utile?

Soluzione

Invece di scriverli foreach loop prova a utilizzare i modelli dell'editor:

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

e all'interno del modello dell'editor corrispondente (~/Views/Shared/EditorTemplates/Product.cshtml)

@model Product
@Html.HiddenFor(x => x.Id)
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top