Две модели в одном представлении в 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) в верхнюю часть блока сохранения / редактирования. . .

JustJohn
источник
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

Мухафил Сайед
источник