Due modelli in una vista in ASP MVC 3


91

Ho 2 modelli:

public class Person
{
    public int PersonID { get; set; }
    public string PersonName { get; set; }
}
public class Order
{
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

Voglio modificare gli oggetti di ENTRAMBE le classi nella vista SINGOLA, quindi ho bisogno di qualcosa come:

@model _try2models.Models.Person
@model _try2models.Models.Order

@using(Html.BeginForm())
{
    @Html.EditorFor(x => x.PersonID)
    @Html.EditorFor(x => x.PersonName)
    @Html.EditorFor(x=>x.OrderID)
    @Html.EditorFor(x => x.TotalSum)
}

Questo, ovviamente, non funziona: è consentita solo un'istruzione "model" in un file .cshtml. Potrebbe esserci qualche soluzione alternativa?


1
La mia risposta ti aiuta?
Andrew

ho usato ViewBagper ciascuno in vista ha funzionato per me, seleziona questo per conoscere più opzioni, risparmiando poco tempo per me invece di creare un modello di visualizzazione o una vista parziale
shaijut

Risposte:


118

Creare un modello di vista padre che contenga entrambi i modelli.

public class MainPageModel{
    public Model1 Model1{get; set;}
    public Model2 Model2{get; set;}
}

In questo modo puoi aggiungere ulteriori modelli in un secondo momento con il minimo sforzo.


2
Quando si utilizza questa soluzione, tenere presente che le modifiche a Model1 o Model2 possono avere un effetto a catena su MainPageModel. Inoltre contengono più dati di quelli di cui la vista ha realmente bisogno. Se la tua MainPage è una combinazione di elementi già presenti in altri controller, il passaggio da RenderPartial a RenderAction ti consentirà di mantenere le cose ben separate. Considera l'idea di leggere la Legge di Demetra: en.wikipedia.org/wiki/Law_of_Demeter
Fenton

1
@Andi - Ho creato il Modello come mi hai suggerito sopra. Ma quando faccio clic con il tasto destro sul controller e provo a creare il controller Crud, non funziona? Eventuali suggerimenti? Come posso creare un controller di crud con visualizzazione automatica per il modello sopra?
NoviceMe

2
Di tutti gli approcci che ho visto per risolvere questo problema, questo è quello che ha funzionato meglio per me. È di gran lunga la soluzione più semplice che funziona.
Ciaran Gallagher

4
Il momento in cui ti chiedi "Perché non ci ho pensato prima?" Ottima soluzione
Rafael AMS

1
@Andi Come espongo i metodi del rispettivo modello nel controller?
Volatil3

53

Per utilizzare la tupla è necessario eseguire le seguenti operazioni, nella vista modificare il modello in:

@model Tuple<Person,Order>

per usare i metodi @html devi fare quanto segue, ad esempio:

@Html.DisplayNameFor(tuple => tuple.Item1.PersonId)

o

@Html.ActionLink("Edit", "Edit", new { id=Model.Item1.Id }) |

Item1 indica il primo parametro passato al metodo Tuple ed è possibile utilizzare Item2 per accedere al secondo modello e così via.

nel tuo controller devi creare una variabile di tipo Tuple e poi passarla alla vista:

    public ActionResult Details(int id = 0)
    {
        Person person = db.Persons.Find(id);
        if (person == null)
        {
            return HttpNotFound();
        }
        var tuple = new Tuple<Person, Order>(person,new Order());

        return View(tuple);
    }

Un altro esempio: più modelli in una vista


1
Non utilizzare mai a Tuplein questo caso: l'OP desidera modificare i dati e a Tuplenon ha un costruttore predefinito, quindi il modello non può essere associato quando il modulo viene inviato

Mai dire mai. È un po 'forte qui.
johnny,

47

Un'altra opzione che non ha la necessità di creare un modello personalizzato consiste nell'usare una tupla <> .

@model Tuple<Person,Order>

Non è così pulito come creare una nuova classe che contiene entrambi, come da risposta di Andi, ma è fattibile.


in mvc 3 dà errore Solo un'istruzione 'model' è consentita in un file. Qualche idea su come risolverlo?
GibboK

1
@ GibboK - Lo sto usando in MVC3 bene. Assicurati di non avere due @modelrighe separate ?
Bobson

3
È possibile ottenere le proprietà di ciascun modello con: @Model.Item1.Propertyand @Model.Item2.Propertyfor Persone Orderrispettivamente
user2019515

1
Ho usato Tuple nella mia vista. Ma non riesco a ottenere i valori del modello nel mio controller. Ma, mentre utilizzavo il modello di visualizzazione padre come consigliato da @Andi, ho ottenuto i valori del modello nel mio controller.
Naren

1
@StephenMuecke - Hmm. Non l'avevo mai considerato, ma hai ragione. Un altro motivo per cui la risposta di Andrew è la migliore per tutti gli usi. Quando si va con un'alternativa leggera (come questo), si fa a rinunciare funzionalità.
Bobson

10

Se sei un fan di avere modelli molto piatti, solo per supportare la vista, dovresti creare un modello specifico per questa particolare vista ...

public class EditViewModel
    public int PersonID { get; set; }
    public string PersonName { get; set; }
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

Molte persone usano AutoMapper per mappare dai loro oggetti di dominio alle loro viste semplici.

L'idea del modello di visualizzazione è che supporta solo la visualizzazione, nient'altro. Ne hai uno per vista per assicurarti che contenga solo ciò che è richiesto per quella vista, non carichi di proprietà che desideri per altre viste.


5

ok, tutti hanno un senso e ho preso tutti i pezzi e li ho messi qui per aiutare i neofiti come me che hanno bisogno di spiegazioni dall'inizio alla fine.

Fai la tua grande classe che contiene 2 classi, come da risposta di @ Andrew.

public class teamBoards{
    public Boards Boards{get; set;}
    public Team Team{get; set;}
}

Quindi nel tuo controller riempi i 2 modelli. A volte devi solo riempirne uno. Quindi nella restituzione, fai riferimento al modello grande e porterà il 2 all'interno con esso alla Vista.

            TeamBoards teamBoards = new TeamBoards();


        teamBoards.Boards = (from b in db.Boards
                               where b.TeamId == id
                               select b).ToList();
        teamBoards.Team = (from t in db.Teams
                              where t.TeamId == id
                          select t).FirstOrDefault();

 return View(teamBoards);

Nella parte superiore della vista

@model yourNamespace.Models.teamBoards

Quindi carica i tuoi input o display facendo riferimento ai contenuti di grandi modelli:

 @Html.EditorFor(m => Model.Board.yourField)
 @Html.ValidationMessageFor(m => Model.Board.yourField, "", new { @class = "text-danger-yellow" })

 @Html.EditorFor(m => Model.Team.yourField)
 @Html.ValidationMessageFor(m => Model.Team.yourField, "", new { @class = "text-danger-yellow" })

E. . . . torna al ranch, quando arriva il Post, fai riferimento alla Big Class:

 public ActionResult ContactNewspaper(teamBoards teamboards)

e utilizzare ciò che i modelli hanno restituito:

string yourVariable = teamboards.Team.yourField;

Probabilmente hanno alcune cose di DataAnnotation Validation nella classe e probabilmente mettono if (ModelState.IsValid) all'inizio del blocco di salvataggio / modifica. . .


4

In effetti c'è un modo per utilizzare due o più modelli in una vista senza racchiuderli in una classe che li contenga entrambi.

Utilizzo di Employee come modello di esempio:

@model Employee

Viene effettivamente trattato come.

@{ var Model = ViewBag.model as Employee; }

Quindi il metodo View (dipendente) sta impostando il tuo modello su ViewBag e quindi ViewEngine lo sta eseguendo.

Ciò significa che,

ViewBag.departments = GetListOfDepartments();
    return View(employee);

Può essere usato come,

            @model  Employee
        @{
                var DepartmentModel = ViewBag.departments as List<Department>;
        }

In sostanza, puoi usare tutto ciò che è nel tuo ViewBag come un "Modello" perché è così che funziona comunque. Non sto dicendo che questo sia architettonicamente ideale, ma è possibile.


3

Basta creare un singolo modello di vista con tutte le informazioni necessarie, normalmente quello che faccio è creare un modello per ogni vista in modo da poter essere specifico su ogni vista, o creare un modello principale ed ereditarlo. OPPURE creare un modello che includa entrambe le viste.

Personalmente li aggiungerei semplicemente in un modello, ma è così che lo faccio:

public class xViewModel
{
    public int PersonID { get; set; }
    public string PersonName { get; set; }
    public int OrderID { get; set; }
    public int TotalSum { get; set; }
}

@model project.Models.Home.xViewModel

@using(Html.BeginForm())
{
    @Html.EditorFor(x => x.PersonID)
    @Html.EditorFor(x => x.PersonName)
    @Html.EditorFor(x => x.OrderID)
    @Html.EditorFor(x => x.TotalSum)
}

1

È possibile utilizzare il modello di presentazione http://martinfowler.com/eaaDev/PresentationModel.html

Questo modello "Visualizza" di presentazione può contenere sia Persona che Ordine, questa nuova
classe può essere il modello a cui fa riferimento la vista.


1
Il modello di presentazione dovrebbe effettivamente contenere i dati richiesti, che possono provenire da una Persona e da un Ordine. In realtà non dovrebbe contenere gli oggetti del dominio Person o Order. La vista disaccoppia la visualizzazione dal dominio sottostante.
Fenton

0

Un altro modo di cui non si parla mai è creare una vista in MSSQL con tutti i dati che si desidera presentare. Quindi utilizzare LINQ to SQL o qualsiasi altra cosa per mapparlo. Nel tuo controller torna alla visualizzazione. Fatto.


0

non puoi dichiarare due modelli su una vista, prova a usare Html.Action("Person", "[YourController]")& Html.Action("Order", "[YourController]").

In bocca al lupo.


Cosa fa questo?
johnny,

0

Oltre a un modello di visualizzazione in asp.net, puoi anche creare più visualizzazioni parziali e assegnare diverse visualizzazioni del modello a ciascuna visualizzazione, ad esempio:

   @{
        Layout = null;
    }

    @model Person;

    <input type="text" asp-for="PersonID" />
    <input type="text" asp-for="PersonName" />

quindi un altro modello di visualizzazione parziale per il modello di ordine

    @{
        Layout = null;
     }

    @model Order;

    <input type="text" asp-for="OrderID" />
    <input type="text" asp-for="TotalSum" />

quindi nella tua vista principale carica entrambe le viste parziali di

<partial name="PersonPartialView" />
<partial name="OrderPartialView" />

-1

Spero che lo trovi utile !!

uso ViewBag per Project e Model per l'attività, quindi in questo modo sto usando due modelli in una vista singola e nel controller ho definito il valore oi dati della viewbag

List<tblproject> Plist = new List<tblproject>();
            Plist = ps.getmanagerproject(c, id);

            ViewBag.projectList = Plist.Select(x => new SelectListItem
            {
                Value = x.ProjectId.ToString(),
                Text = x.Title
            });

e in vista tbltask e projectlist sono i miei due modelli di diff

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} @model List

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.