Dwa modele w jednym widoku w ASP MVC 3


92

Mam 2 modele:

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

Chcę edytować obiekty OBU klas w widoku SINGLE, więc potrzebuję czegoś takiego:

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

To oczywiście nie działa: tylko jedna instrukcja „model” jest dozwolona w pliku .cshtml. Może istnieje jakieś obejście?


1
Czy moja odpowiedź ci pomaga?
— Andrew,

użyłem ViewBagz dla każdego w widoku działało dla mnie, sprawdź to, aby poznać wiele opcji, zaoszczędziłem trochę czasu zamiast tworzyć model widoku lub częściowy widok
— shaijut

Odpowiedzi:


119

Utwórz nadrzędny model widoku, który zawiera oba modele.

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

W ten sposób możesz dodać dodatkowe modele w późniejszym terminie przy minimalnym wysiłku.


2
Korzystając z tego rozwiązania, należy pamiętać, że zmiany w Model1 lub Model2 mogą mieć wpływ na Twój MainPageModel. Ponadto zawierają one więcej danych, niż naprawdę potrzebuje widok. Jeśli twoja MainPage jest kombinacją rzeczy, które są już w innych kontrolerach, przełączenie z RenderPartial na RenderAction pozwoli ci zachować porządek. Rozważ przeczytanie na temat Prawa Demeter: en.wikipedia.org/wiki/Law_of_Demeter
— Fenton

1
@Andi - stworzyłem Model, jak sugerowałeś powyżej. Ale kiedy klikam prawym przyciskiem myszy kontroler i próbuję utworzyć kontroler Crud, nie działa? Jakieś sugestie? Jak mogę stworzyć kontroler Crud z automatycznym podglądem dla powyższego modelu?
— NoviceMe

2
Ze wszystkich podejść, które widziałem, aby rozwiązać ten problem, ta była dla mnie najlepsza. To zdecydowanie najprostsze rozwiązanie, które działa.
— Ciaran Gallagher

4
Moment, kiedy zadajesz sobie pytanie „Dlaczego wcześniej o tym nie pomyślałem?” Świetne rozwiązanie
— Rafael AMS

1
@Andi Jak wyeksponować metody odpowiedniego modelu w kontrolerze?
— Volatil3

53

Aby użyć krotki, musisz wykonać następujące czynności, w widoku zmień model na:

@model Tuple<Person,Order>

aby użyć metod @html, musisz wykonać następujące czynności, np .:

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

lub

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

Item1 wskazuje pierwszy parametr przekazany do metody Tuple i można użyć Item2, aby uzyskać dostęp do drugiego modelu i tak dalej.

w kontrolerze musisz utworzyć zmienną typu Tuple i przekazać ją do widoku:

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

Inny przykład: wiele modeli w widoku


1
Nigdy nie używaj Tuplew tym przypadku - OP chce edytować dane, a Tuplenie ma domyślnego konstruktora, więc model nie może być powiązany po przesłaniu formularza

Nigdy nie mów nigdy. To trochę mocne tutaj.
— johnny

47

Inną opcją, która nie wymaga tworzenia modelu niestandardowego, jest użycie krotki <> .

@model Tuple<Person,Order>

Nie jest to tak proste, jak tworzenie nowej klasy, która zawiera oba, zgodnie z odpowiedzią Andiego, ale jest wykonalne.


w mvc 3 daje błąd Tylko jedna instrukcja „model” jest dozwolona w pliku. Masz jakiś pomysł, jak to rozwiązać?
— GibboK

1
@GibboK - używam go w MVC3 w porządku. Upewnij się, że nie masz dwóch oddzielnych @modelwierszy?
— Bobson

3
Możesz uzyskać właściwości każdego Modelu za pomocą: @Model.Item1.Propertyi @Model.Item2.Propertydla Personi Orderodpowiednio
— user2019515

1
Użyłem krotki w moim widoku. Ale nie mogę uzyskać wartości modelu w moim kontrolerze. Ale kiedy używam modelu widoku nadrzędnego zgodnie z zaleceniami @Andi, otrzymałem wartości modelu w moim kontrolerze.
— Naren

1
@StephenMuecke - Hmm. Nigdy o tym nie myślałem, ale masz rację. Kolejny powód, dla którego odpowiedź Andrzeja jest lepsza, uniwersalna. Kiedy iść z alternatywą lekkiego (jak to), to nie dać się funkcjonalność.
— Bobson

10

Jeśli jesteś fanem bardzo płaskich modeli, aby podeprzeć widok, powinieneś stworzyć model specyficzny dla tego konkretnego widoku ...

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

Wiele osób używa AutoMappera do mapowania z obiektów domeny do płaskich widoków.

Idea modelu widoku polega na tym, że po prostu obsługuje widok - nic więcej. Masz jeden widok na widok, aby upewnić się, że zawiera on tylko to, co jest wymagane dla tego widoku - a nie mnóstwo właściwości, które chcesz mieć w innych widokach.


5

ok, wszyscy mają sens i wziąłem wszystkie elementy i umieściłem je tutaj, aby pomóc nowicjuszom takim jak ja, którzy potrzebują początku i końca wyjaśnienia.

Tworzysz swoją dużą klasę, która ma 2 klasy, zgodnie z odpowiedzią @ Andrew.

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

Następnie w kontrolerze wypełniasz 2 modele. Czasami wystarczy wypełnić jeden. Następnie w zamian odwołujesz się do dużego modelu i zabierze on 2 ze sobą do widoku.

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

U góry widoku

@model yourNamespace.Models.teamBoards

Następnie załaduj dane wejściowe lub ekrany odwołujące się do zawartości dużych modeli:

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

I. . . . z powrotem na ranczo, kiedy pojawi się poczta, odwołaj się do Big Class:

 public ActionResult ContactNewspaper(teamBoards teamboards)

i wykorzystaj to, co zwrócił model (y):

string yourVariable = teamboards.Team.yourField;

Prawdopodobnie mają w klasie jakieś rzeczy DataAnnotation Validation i prawdopodobnie umieść if (ModelState.IsValid) na górze bloku zapisu / edycji. . .


4

W rzeczywistości istnieje sposób na użycie dwóch lub więcej modeli w jednym widoku bez pakowania ich w klasę, która zawiera oba.

Na przykładzie pracownika:

@model Employee

Tak naprawdę jest traktowany.

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

Tak więc metoda View (pracownik) ustawia model na ViewBag, a następnie ViewEngine go rzutuje.

To znaczy że,

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

Może być używany jak

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

Zasadniczo możesz użyć tego, co znajduje się w Twoim ViewBag, jako „Modelu”, ponieważ i tak to działa. Nie twierdzę, że jest to architektonicznie idealne, ale jest to możliwe.


3

Po prostu stwórz pojedynczy model widoku z wszystkimi potrzebnymi informacjami, zwykle tworzę model dla każdego widoku, więc mogę być specyficzny dla każdego widoku, albo utworzyć model nadrzędny i dziedziczyć go. LUB utwórz model, który zawiera oba widoki.

Osobiście po prostu dodałbym je do jednego modelu, ale tak to robię:

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

Możesz użyć wzorca prezentacji http://martinfowler.com/eaaDev/PresentationModel.html

Ten model „Widok” prezentacji może zawierać zarówno Person, jak i Order, ta nowa
klasa może być modelem, do którego odwołuje się widok.


1
Model prezentacji powinien faktycznie zawierać wymagane dane, które mogą pochodzić od Osoby i Zamówienia. W rzeczywistości nie powinien zawierać obiektów domeny Person ani Order. Widok oddziela wyświetlanie od podstawowej domeny.
— Fenton

0

Innym sposobem, o którym nigdy się nie mówi, jest utworzenie widoku w MSSQL ze wszystkimi danymi, które chcesz przedstawić. Następnie użyj LINQ to SQL lub cokolwiek innego, aby go zmapować. W kontrolerze przywróć go do widoku. Gotowe.


0

nie możesz zadeklarować dwóch modeli w jednym widoku, spróbuj użyć Html.Action("Person", "[YourController]")& Html.Action("Order", "[YourController]").

Powodzenia.


Co to robi?
— johnny

0

Oprócz jednego modelu widoku w asp.net możesz również utworzyć wiele widoków częściowych i przypisać inny widok modelu do każdego widoku, na przykład:

   @{
        Layout = null;
    }

    @model Person;

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

następnie inny częściowy widok Model dla modelu zamówienia

    @{
        Layout = null;
     }

    @model Order;

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

następnie w głównym widoku załaduj oba częściowe widoki według

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

-1

Mam nadzieję, że okaże się to pomocne!

używam ViewBag For Project i Model do zadania, więc w ten sposób używam dwóch modeli w jednym widoku i kontrolerze zdefiniowałem wartość lub dane 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
            });

a w widoku tbltask i projectlist to moje dwa modele różnic

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} @model List

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.