Zwei Modelle in einer Ansicht in ASP MVC 3

91

Ich habe 2 Modelle:

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

Ich möchte Objekte von BEIDEN Klassen in der EINZELNEN Ansicht bearbeiten, daher benötige ich Folgendes:

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

Dies funktioniert natürlich nicht: In einer .cshtml-Datei ist nur eine 'model'-Anweisung zulässig. Möglicherweise gibt es eine Problemumgehung?

Smarty
quelle
1
Hilft Ihnen meine Antwort?
Andrew
Ich habe ViewBagmit für jede Ansicht für mich gearbeitet, überprüfen Sie dies , um mehrere Optionen zu kennen, sparte wenig Zeit für mich, anstatt ein Ansichtsmodell oder eine Teilansicht zu
erstellen

Antworten:

118

Erstellen Sie ein übergeordnetes Ansichtsmodell, das beide Modelle enthält.

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

Auf diese Weise können Sie zu einem späteren Zeitpunkt mit minimalem Aufwand weitere Modelle hinzufügen.

Andrew
quelle
2
Beachten Sie bei der Verwendung dieser Lösung, dass Änderungen an Modell1 oder Modell2 Auswirkungen auf Ihr MainPageModel haben können. Außerdem enthalten sie hauptsächlich mehr Daten, als die Ansicht wirklich benötigt. Wenn Ihre MainPage eine Kombination von Dingen ist, die sich bereits in anderen Controllern befinden, können Sie durch den Wechsel von RenderPartial zu RenderAction die Dinge sauber voneinander trennen. Lesen Sie das Gesetz von Demeter nach: en.wikipedia.org/wiki/Law_of_Demeter
Fenton
1
@Andi - Ich habe das Modell wie oben vorgeschlagen erstellt. Aber wenn ich mit der rechten Maustaste auf den Controller klicke und versuche, einen Crud-Controller zu erstellen, funktioniert er nicht? Irgendwelche Vorschläge? Wie kann ich eine Rohölsteuerung mit automatischer Ansicht für das obige Modell erstellen?
NoviceMe
2
Von allen Ansätzen, die ich zur Lösung dieses Problems gesehen habe, hat dieser für mich am besten funktioniert. Es ist bei weitem die einfachste Lösung, die funktioniert.
Ciaran Gallagher
4
Der Moment, in dem Sie sich fragen: "Warum habe ich vorher nicht daran gedacht?" Tolle Lösung
Rafael AMS
1
@Andi Wie würde ich Methoden des jeweiligen Modells in Controller verfügbar machen?
Volatil3
53

Um das Tupel zu verwenden, müssen Sie Folgendes tun: Ändern Sie in der Ansicht das Modell in:

@model Tuple<Person,Order>

Um @ html-Methoden zu verwenden, müssen Sie Folgendes tun:

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

oder

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

Item1 gibt den ersten Parameter an, der an die Tuple-Methode übergeben wurde. Mit Item2 können Sie auf das zweite Modell zugreifen und so weiter.

In Ihrem Controller müssen Sie eine Variable vom Typ Tuple erstellen und diese dann an die Ansicht übergeben:

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

Ein weiteres Beispiel: Mehrere Modelle in einer Ansicht

Hamid Tavakoli
quelle
1
Verwenden Sie Tuplein diesem Fall niemals a - OP möchte Daten bearbeiten, und a Tuplehat keinen Standardkonstruktor, sodass das Modell beim
Sag niemals nie. Das ist hier ein bisschen stark.
Johnny
47

Eine andere Option, bei der kein benutzerdefiniertes Modell erstellt werden muss, ist die Verwendung eines Tupels <> .

@model Tuple<Person,Order>

Es ist nicht so sauber wie das Erstellen einer neuen Klasse, die laut Andis Antwort beides enthält, aber es ist realisierbar.

Bobson
quelle
In MVC 3 wird ein Fehler ausgegeben. In einer Datei ist nur eine 'Modell'-Anweisung zulässig. Irgendeine Idee, wie man es löst?
GibboK
1
@ GibboK - Ich benutze es in MVC3 ganz gut. Stellen Sie sicher, dass Sie keine zwei getrennten @modelZeilen haben?
Bobson
3
Sie können die Eigenschaften jedes Modell mit bekommen: @Model.Item1.Propertyund @Model.Item2.Propertyfür Personund Orderjeweils
user2019515
1
Ich habe Tuple in meiner Ansicht verwendet. Ich kann die Modellwerte jedoch nicht in meinem Controller abrufen. Aber während ich das übergeordnete Ansichtsmodell wie von @Andi empfohlen verwendet habe, habe ich die Modellwerte in meinem Controller erhalten.
Naren
1
@ StephenMuecke - Hmm. Ich hatte das nie in Betracht gezogen, aber du hast recht. Ein weiterer Grund, warum Andrews Antwort die bessere für allgemeine Zwecke ist. Wenn Sie sich für eine leichte Alternative (wie diese) entscheiden, geben Sie die Funktionalität auf.
Bobson
10

Wenn Sie ein Fan von sehr flachen Modellen sind, sollten Sie zur Unterstützung der Ansicht ein Modell erstellen, das für diese bestimmte Ansicht spezifisch ist ...

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

Viele Benutzer verwenden AutoMapper, um ihre Domänenobjekte ihren flachen Ansichten zuzuordnen.

Die Idee des Ansichtsmodells ist, dass es nur die Ansicht unterstützt - sonst nichts. Sie haben eine pro Ansicht, um sicherzustellen, dass sie nur das enthält, was für diese Ansicht erforderlich ist - nicht viele Eigenschaften, die Sie für andere Ansichten benötigen.

Fenton
quelle
5

ok, jeder macht Sinn und ich habe alle Teile genommen und hierher gebracht, um Neulingen wie mir zu helfen, die eine Erklärung von Anfang bis Ende benötigen.

Sie machen Ihre große Klasse, die 2 Klassen enthält, gemäß @ Andrews Antwort.

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

Dann füllen Sie in Ihrem Controller die 2 Modelle. Manchmal müssen Sie nur eine füllen. In der Rückgabe verweisen Sie dann auf das große Modell und es nimmt die 2 im Inneren mit zur Ansicht.

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

Oben in der Ansicht

@model yourNamespace.Models.teamBoards

Laden Sie dann Ihre Eingaben oder Anzeigen, die auf den Inhalt der großen Modelle verweisen:

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

Und. . . Zurück auf der Ranch, wenn die Post hereinkommt, verweisen Sie auf die große Klasse:

 public ActionResult ContactNewspaper(teamBoards teamboards)

und nutzen Sie, was die Modelle zurückgegeben haben:

string yourVariable = teamboards.Team.yourField;

Haben Sie wahrscheinlich einige DataAnnotation Validation-Inhalte in der Klasse und setzen Sie if (ModelState.IsValid) oben in den Speicher- / Bearbeitungsblock. . .

JustJohn
quelle
4

Tatsächlich gibt es eine Möglichkeit, zwei oder mehr Modelle in einer Ansicht zu verwenden, ohne sie in eine Klasse einzuschließen, die beide enthält.

Verwenden des Mitarbeiters als Beispielmodell:

@model Employee

Wird eigentlich wie behandelt.

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

Die View-Methode (Mitarbeiter) setzt Ihr Modell also auf ViewBag und wird dann von ViewEngine umgewandelt.

Dies bedeutet, dass,

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

Kann verwendet werden wie

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

Im Wesentlichen können Sie alles, was sich in Ihrem ViewBag befindet, als "Modell" verwenden, da dies sowieso so funktioniert. Ich sage nicht, dass dies architektonisch ideal ist, aber es ist möglich.

Alex Tselevich
quelle
3

Erstellen Sie einfach ein einzelnes Ansichtsmodell mit allen erforderlichen Informationen. Normalerweise erstelle ich für jede Ansicht ein Modell, damit ich für jede Ansicht spezifisch sein kann, entweder für diese Ansicht, oder ein übergeordnetes Modell erstellen und es erben kann. ODER erstellen Sie ein Modell, das beide Ansichten enthält.

Persönlich würde ich sie nur zu einem Modell hinzufügen, aber so mache ich es:

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

Sie können das Präsentationsmuster http://martinfowler.com/eaaDev/PresentationModel.html verwenden

Dieses Präsentationsmodell "Ansicht" kann sowohl Person als auch Reihenfolge enthalten. Diese neue
Klasse kann das Modell sein, auf das Ihre Ansicht verweist.

James Kyburz
quelle
1
Das Präsentationsmodell sollte tatsächlich die erforderlichen Daten enthalten, die von einer Person und einer Bestellung stammen können. Es sollte nicht wirklich die Personen- oder Auftragsdomänenobjekte enthalten. Die Ansicht entkoppelt die Anzeige von der zugrunde liegenden Domäne.
Fenton
0

Eine andere Möglichkeit, über die nie gesprochen wird, ist das Erstellen einer Ansicht in MSSQL mit allen Daten, die Sie präsentieren möchten. Verwenden Sie dann LINQ to SQL oder was auch immer, um es zuzuordnen. In Ihrem Controller kehren Sie zur Ansicht zurück. Getan.

versteckt
quelle
0

Sie können nicht zwei Modelle in einer Ansicht deklarieren. Versuchen Sie, Html.Action("Person", "[YourController]")& zu verwenden Html.Action("Order", "[YourController]").

Viel Glück.

Jimmy Mac
quelle
Was macht das?
Johnny
0

Neben einem Ansichtsmodell in asp.net können Sie auch mehrere Teilansichten erstellen und jeder Ansicht eine andere Modellansicht zuweisen, zum Beispiel:

   @{
        Layout = null;
    }

    @model Person;

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

dann eine weitere Teilansicht Modell für Bestellmodell

    @{
        Layout = null;
     }

    @model Order;

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

Laden Sie dann in Ihrer Hauptansicht beide Teilansichten von

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

Ich hoffe du findest es hilfreich !!

Ich verwende ViewBag für Projekt und Modell für Aufgabe. Auf diese Weise verwende ich zwei Modelle in einer Ansicht und in der Steuerung. Ich definiere den Wert oder die Daten von 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
            });

und in view tbltask und projectlist sind meine beiden diff modelle

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} @modell List

Muhafil Saiyed
quelle