Две модели в одном представлении в ASP MVC 3


92

У меня 2 модели:

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

Я хочу редактировать объекты ОБЕИХ классов в ОДНОМ представлении, поэтому мне нужно что-то вроде:

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

Это, конечно, не работает: в файле .cshtml допускается только одно «модельное» выражение. Может быть есть обходной путь?


1
Мой ответ тебе помогает?
— Эндрю

Я использовал, ViewBagчтобы каждый вид работал у меня, проверьте это, чтобы узнать несколько вариантов, сэкономил немного времени для меня вместо создания модели представления или частичного представления
— Шайджут

Ответы:


119

Создайте родительскую модель представления, содержащую обе модели.

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

Таким образом, вы можете добавить дополнительные модели позже с минимальными усилиями.


2
При использовании этого решения имейте в виду, что изменения в Model1 или Model2 могут повлиять на вашу MainPageModel. Кроме того, они содержат больше данных, чем действительно нужно представлению. Если ваша MainPage представляет собой комбинацию вещей, которые уже есть в других контроллерах, переключение с RenderPartial на RenderAction позволит вам аккуратно разделить элементы. Вы можете прочитать о законе Деметры: en.wikipedia.org/wiki/Law_of_Demeter
— Фентон,

1
@Andi - Я создал Модель, как вы предложили выше. Но когда я щелкаю правой кнопкой мыши на контроллере и пытаюсь создать контроллер Crud, он не работает? Какие-либо предложения? Как я могу создать контроллер crud с автоматическим представлением для вышеуказанной модели?
— NoviceMe

2
Из всех подходов, которые я видел для решения этой проблемы, мне больше всего подошел этот. Это, безусловно, самое простое решение, которое работает.
— Ciaran Gallagher

4
Момент, когда вы спрашиваете себя: «Почему я не подумал об этом раньше?» Отличное решение
— Rafael AMS

1
@Andi Как мне раскрыть методы соответствующей модели в контроллере?
— Volatil3

53

Чтобы использовать кортеж, вам необходимо сделать следующее, в представлении измените модель на:

@model Tuple<Person,Order>

чтобы использовать методы @html, вам необходимо сделать следующее, например:

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

или

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

Item1 указывает первый параметр, переданный в метод Tuple, и вы можете использовать Item2 для доступа ко второй модели и так далее.

в вашем контроллере вам нужно создать переменную типа Tuple, а затем передать ее представлению:

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

Другой пример: несколько моделей на виде


1
Никогда не используйте a Tupleв этом случае - OP хочет редактировать данные, а a Tupleне имеет конструктора по умолчанию, поэтому модель не может быть привязана при

Никогда не говори никогда. Здесь немного сильновато.
— джонни

47

Другой вариант, при котором нет необходимости создавать настраиваемую модель, - это использовать Tuple <> .

@model Tuple<Person,Order>

Это не так чисто, как создание нового класса, который содержит оба, согласно ответу Анди, но это жизнеспособно.


в mvc 3 это дает ошибку. В файле разрешен только один оператор "модель". Есть идеи, как это решить?
— GibboK

1
@GibboK - Я отлично использую его в MVC3. Убедитесь, что у вас нет двух отдельных @modelстрок?
— Bobson

3
Вы можете получить свойства каждой модели с помощью: @Model.Item1.Propertyи @Model.Item2.Propertyдля Personи Orderсоответственно
— user2019515

1
Я использовал Tuple в своем представлении. Но я не могу получить значения модели в своем контроллере. Но, хотя я использовал модель родительского представления, как рекомендовал @Andi, я получил значения модели в своем контроллере.
— Нарен

1
@StephenMuecke - Хм. Я никогда не думал об этом, но ты прав. Еще одна причина того, что ответ Эндрю лучше универсален. Когда вы идете с облегченной альтернативой (как это), вы бы отказаться от функциональности.
— Bobson

10

Если вы поклонник очень плоских моделей, просто для поддержки вида вам следует создать модель, специфичную для этого конкретного вида ...

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

Многие люди используют AutoMapper для отображения объектов своей области на плоские представления.

Идея модели представления состоит в том, что она просто поддерживает представление - ничего больше. У вас есть по одному на представление, чтобы гарантировать, что оно содержит только то, что требуется для этого представления, а не множество свойств, которые вы хотите для других представлений.


5

хорошо, все имеют смысл, и я взял все части и положил их сюда, чтобы помочь новичкам, таким как я, которым нужно начало и конец объяснения.

Вы делаете свой большой класс, содержащий 2 класса, согласно ответу @ Andrew.

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

Затем в вашем контроллере заливаете 2 модели. Иногда нужно заполнить только одну. Затем, в ответ, вы ссылаетесь на большую модель, и она возьмет 2 внутри с собой в View.

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

Вверху просмотра

@model yourNamespace.Models.teamBoards

Затем загрузите свои входы или дисплеи, ссылающиеся на большое содержимое моделей:

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

А также. . . . Вернувшись на ранчо, когда придет почта, укажите Большой класс:

 public ActionResult ContactNewspaper(teamBoards teamboards)

и использовать то, что вернула модель (ы):

string yourVariable = teamboards.Team.yourField;

Возможно, в классе есть какой-то материал для проверки DataAnnotation и, возможно, поместите if (ModelState.IsValid) в верхнюю часть блока сохранения / редактирования. . .


4

Фактически, есть способ использовать две или более моделей в одном представлении, не помещая их в класс, содержащий обе.

Использование Employee в качестве примера модели:

@model Employee

Собственно обращаются как.

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

Таким образом, метод View (сотрудник) устанавливает вашу модель в ViewBag, а затем ViewEngine выполняет ее преобразование.

Это значит, что,

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

Может использоваться как,

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

По сути, вы можете использовать все, что находится в вашем ViewBag, в качестве «модели», потому что так оно и есть в любом случае. Я не говорю, что это архитектурно идеально, но это возможно.


3

Просто создайте единую модель представления со всей необходимой информацией в ней, обычно я создаю модель для каждого представления, чтобы я мог быть конкретным для каждого представления, либо это, либо создать родительскую модель и наследовать ее. ИЛИ создайте модель, включающую оба вида.

Лично я бы просто добавил их в одну модель, но я это делаю так:

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

Вы можете использовать шаблон презентации http://martinfowler.com/eaaDev/PresentationModel.html

Эта модель представления "View" может содержать как Person, так и Order, этот новый
класс может быть моделью, на которую ссылается ваше представление.


1
Модель презентации должна фактически содержать необходимые данные, которые могут исходить от человека и заказа. На самом деле он не должен содержать объекты домена Person или Order. Представление отделяет отображение от базового домена.
— Fenton

0

Другой способ, о котором никогда не говорят, - это создать представление в MSSQL со всеми данными, которые вы хотите представить. Затем используйте LINQ to SQL или что-то еще, чтобы сопоставить его. В вашем контроллере верните его в представление. Выполнено.


0

вы не можете объявить две модели в одном представлении, попробуйте использовать Html.Action("Person", "[YourController]")& Html.Action("Order", "[YourController]").

Удачи.


Что это значит?
— джонни

0

Помимо одной модели представления в asp.net вы также можете создать несколько частичных представлений и назначить разные представления модели каждому представлению, например:

   @{
        Layout = null;
    }

    @model Person;

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

затем еще одна модель частичного представления для модели заказа

    @{
        Layout = null;
     }

    @model Order;

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

затем в главном представлении загрузите оба частичных представления

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

-1

Я надеюсь, вы найдете это полезным !!

Я использую ViewBag для проекта и модель для задачи, поэтому я использую две модели в одном представлении, а в контроллере я определил значение или данные 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
            });

и в виду tbltask и projectlist - мои две модели различий

@ {

IEnumerable<SelectListItem> plist = ViewBag.projectList;

} @model List

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.