Deux modèles dans une vue dans ASP MVC 3

91

J'ai 2 modèles:

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

Je veux éditer les objets des DEUX classes en vue UNIQUE, j'ai donc besoin de quelque chose comme:

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

Ceci, bien sûr, ne fonctionne pas: une seule instruction 'model' est autorisée dans un fichier .cshtml. Peut-être existe-t-il une solution de contournement?

Smarty
la source
1
Ma réponse vous aide-t-elle?
Andrew
J'ai utilisé ViewBagavec pour chaque vue a fonctionné pour moi, vérifiez ceci pour connaître plusieurs options, économisé peu de temps pour moi au lieu de créer un modèle de vue ou une vue partielle
shaijut

Réponses:

118

Créez un modèle de vue parent qui contient les deux modèles.

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

De cette façon, vous pouvez ajouter des modèles supplémentaires à une date ultérieure avec un minimum d'effort.

Andrew
la source
2
Lorsque vous utilisez cette solution, gardez à l'esprit que les modifications apportées à Model1 ou Model2 peuvent avoir un effet sur votre MainPageModel. Ils contiennent également plus de données que la vue n'en a vraiment besoin. Si votre MainPage est une combinaison d'éléments qui se trouvent déjà dans d'autres contrôleurs, le passage de RenderPartial à RenderAction vous permettra de garder les choses soigneusement séparées. Pensez à lire la loi de Demeter: en.wikipedia.org/wiki/Law_of_Demeter
Fenton
1
@Andi - J'ai créé le modèle comme vous l'avez suggéré ci-dessus. Mais lorsque je clique avec le bouton droit sur le contrôleur et que j'essaie de créer un contrôleur Crud, cela ne fonctionne pas? Aucune suggestion? Comment puis-je créer un contrôleur de crud avec vue automatique pour le modèle ci-dessus?
NoviceMe
2
De toutes les approches que j'ai vues pour résoudre ce problème, c'est celle qui a le mieux fonctionné pour moi. C'est de loin la solution la plus simple qui fonctionne.
Ciaran Gallagher
4
Le moment où vous vous demandez "Pourquoi n'y ai-je pas pensé avant?" Excellente solution
Rafael AMS
1
@Andi Comment exposerais-je les méthodes du modèle respectif dans le contrôleur?
Volatil3
53

Pour utiliser le tuple, vous devez effectuer les opérations suivantes, dans la vue, changez le modèle en:

@model Tuple<Person,Order>

pour utiliser les méthodes @html, vous devez procéder comme suit:

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

ou

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

Item1 indique le premier paramètre passé à la méthode Tuple et vous pouvez utiliser Item2 pour accéder au deuxième modèle et ainsi de suite.

dans votre contrôleur, vous devez créer une variable de type Tuple puis la passer à la vue:

    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 autre exemple: plusieurs modèles dans une vue

Hamid Tavakoli
la source
1
Ne jamais utiliser a Tupledans ce cas - OP veut éditer des données, et a Tuplen'a pas de constructeur par défaut donc le modèle ne peut pas être lié lorsque le formulaire est soumis
Ne jamais dire jamais. C'est un peu fort ici.
johnny
47

Une autre option qui n'a pas besoin de créer un modèle personnalisé consiste à utiliser un Tuple <> .

@model Tuple<Person,Order>

Ce n'est pas aussi clair que de créer une nouvelle classe qui contient les deux, selon la réponse d'Andi, mais c'est viable.

Bobson
la source
dans mvc 3, cela donne une erreur Une seule instruction «modèle» est autorisée dans un fichier. Une idée de comment le résoudre?
GibboK
1
@GibboK - Je l'utilise très bien dans MVC3. Assurez-vous que vous n'avez pas deux @modellignes distinctes ?
Bobson
3
Vous pouvez obtenir les propriétés de chaque modèle avec: @Model.Item1.Propertyet @Model.Item2.Propertypour Personet Orderrespectivement
user2019515
1
J'ai utilisé Tuple dans ma vue. Mais, je ne peux pas obtenir les valeurs du modèle dans mon contrôleur. Mais, alors que j'utilise le modèle de vue Parent comme recommandé par @Andi, j'ai les valeurs du modèle dans mon contrôleur.
Naren
1
@StephenMuecke - Hmm. Je n'avais jamais pensé à ça, mais tu as raison. Une autre raison pour laquelle la réponse d'Andrew est la meilleure à usage général. Quand vous allez à une alternative léger (comme ça), vous ne renoncez fonctionnalité.
Bobson
10

Si vous êtes fan des modèles très plats, juste pour soutenir la vue, vous devez créer un modèle spécifique à cette vue particulière ...

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

De nombreuses personnes utilisent AutoMapper pour mapper les objets de leur domaine vers leurs vues à plat.

L'idée du modèle de vue est qu'il ne prend en charge que la vue - rien d'autre. Vous en avez une par vue pour vous assurer qu'elle ne contient que ce qui est requis pour cette vue, et non les nombreuses propriétés que vous souhaitez pour d'autres vues.

Fenton
la source
5

ok, tout le monde a du sens et j'ai pris toutes les pièces et les ai mises ici pour aider les débutants comme moi qui ont besoin d'explications du début à la fin.

Vous créez votre grande classe qui contient 2 classes, selon la réponse de @ Andrew.

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

Ensuite, dans votre contrôleur, vous remplissez les 2 modèles. Parfois, il suffit d'en remplir un. Puis dans le retour, vous référencez le grand modèle et il emportera le 2 à l'intérieur avec lui à la vue.

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

En haut de la vue

@model yourNamespace.Models.teamBoards

Ensuite, chargez vos entrées ou affichages référençant le contenu des grands modèles:

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

Et. . . . de retour au ranch, lorsque la poste arrive, faites référence à la grande classe:

 public ActionResult ContactNewspaper(teamBoards teamboards)

et utilisez ce que le ou les modèles ont renvoyé:

string yourVariable = teamboards.Team.yourField;

Avoir probablement des éléments de validation DataAnnotation dans la classe et probablement mettre if (ModelState.IsValid) en haut du bloc de sauvegarde / modification. . .

JustJohn
la source
4

En fait, il existe un moyen d'utiliser deux ou plusieurs modèles sur une vue sans les envelopper dans une classe qui contient les deux.

Utiliser Employee comme exemple de modèle:

@model Employee

Est en fait traité comme.

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

Ainsi, la méthode View (employé) définit votre modèle sur le ViewBag, puis le ViewEngine le transforme.

Cela signifie que,

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

Peut être utilisé comme,

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

Essentiellement, vous pouvez utiliser tout ce qui se trouve dans votre ViewBag comme "modèle", car c'est ainsi que cela fonctionne de toute façon. Je ne dis pas que c'est architecturalement idéal, mais c'est possible.

Alex Tselevich
la source
3

Créez simplement un modèle de vue unique avec toutes les informations nécessaires, ce que je fais normalement est de créer un modèle pour chaque vue afin que je puisse être spécifique sur chaque vue, que ce soit cela ou créer un modèle parent et en hériter. OU créez un modèle qui inclut les deux vues.

Personnellement, je les ajouterais simplement dans un seul modèle, mais c'est comme ça que je le fais:

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)
}
Michael
la source
1

Vous pouvez utiliser le modèle de présentation http://martinfowler.com/eaaDev/PresentationModel.html

Ce modèle de présentation "Vue" peut contenir à la fois Person et Order, cette nouvelle
classe peut être le modèle de référence de votre vue.

James Kyburz
la source
1
Le modèle de présentation doit en fait contenir les données requises, qui peuvent provenir d'une personne et d'une commande. Il ne doit pas vraiment contenir les objets de domaine Person ou Order. La vue dissocie l'affichage du domaine sous-jacent.
Fenton
0

Une autre façon dont on ne parle jamais est de créer une vue dans MSSQL avec toutes les données que vous souhaitez présenter. Ensuite, utilisez LINQ to SQL ou autre pour le mapper. Dans votre contrôleur, retournez-le à la vue. Terminé.

caché
la source
0

vous ne pouvez pas déclarer deux modèles sur une vue, essayez d'utiliser Html.Action("Person", "[YourController]")&Html.Action("Order", "[YourController]") .

Bonne chance.

Jimmy Mac
la source
Qu'est ce que cela fait?
johnny
0

En plus d'un modèle de vue dans asp.net, vous pouvez également créer plusieurs vues partielles et affecter une vue de modèle différente à chaque vue, par exemple:

   @{
        Layout = null;
    }

    @model Person;

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

puis un autre modèle de vue partielle pour le modèle de commande

    @{
        Layout = null;
     }

    @model Order;

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

puis dans votre vue principale, chargez les deux vues partielles en

<partial name="PersonPartialView" />
<partial name="OrderPartialView" />
Liam
la source
-1

J'espère que vous le trouverez utile !!

J'utilise ViewBag For Project et Model pour la tâche, donc de cette manière j'utilise deux modèles en vue unique et dans le contrôleur, j'ai défini la valeur ou les données de 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
            });

et en vue tbltask et projectlist sont mes deux modèles de diff

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} Liste @model

Muhafil Saiyed
la source