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?

Smarty
źródło
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.

Andrzej
źródło
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

Hamid Tavakoli
źródło
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.

Bobson
źródło
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.

Fenton
źródło
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. . .

JustJohn
źródło
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.

Alex Tselevich
źródło
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)
}
Michał
źródło
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.

James Kyburz
źródło
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.

ukryty
źródło
0

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

Powodzenia.

Jimmy Mac
źródło
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" />
Shojaeddin
źródło
-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

Muhafil Saiyed
źródło