Дві моделі в одному вигляді в ASP MVC 3


91

У мене 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 допускається лише одне твердження "model". Може бути, є якесь обхідне рішення?


1
Чи допомагає вам моя відповідь?
— Ендрю

я використовував ViewBagдля кожного з оглядів, які працювали для мене, перевірте це, щоб знати кілька варіантів, заощадили для мене мало часу, замість створення моделі перегляду або часткового перегляду
— shaijut,

Відповіді:


118

Створіть батьківську модель подання, яка містить обидві моделі.

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
Момент, коли ви запитуєте себе: "Чому я не думав про це раніше?" Чудове рішення
— Рафаель АМС

1
@Andi Як мені виставити методи відповідної моделі в контролері?
— Volatil3

53

Щоб використовувати кортеж, потрібно зробити наступне, у поданні змінити модель на:

@model Tuple<Person,Order>

для використання методів @html потрібно зробити наступне, тобто:

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

або

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

Позиція 1 вказує на перший параметр, переданий методу 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 він видає помилку У файлі допускається лише одне твердження "model". Будь-яка ідея, як це вирішити?
— GibboK

1
@GibboK - Я використовую його в MVC3 просто чудово. Переконайтесь, що у вас немає двох окремих @modelрядків?
— Бобсон,

3
Ви можете отримати властивості кожної Моделі за допомогою: @Model.Item1.Propertyі @Model.Item2.Propertyдля, Personі Orderвідповідно
— user2019515

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

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

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 всередині з собою до подання.

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

І. . . .back на ранчо, коли заходить Пошта, посилання на Великий Клас:

 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

Ця модель презентації "Перегляд" може містити як особу, так і замовлення, цей новий
клас може бути моделлю, на яку посилається ваш погляд.


1
Модель презентації фактично повинна містити необхідні дані, які можуть походити від Особи та Наказу. Він насправді не повинен містити об'єкти домену Person або Order. Вигляд відокремлює дисплей від базового домену.
— Фентон,

0

Інший спосіб, про який ніколи не говорять, - це створення подання в MSSQL з усіма даними, які ви хочете представити. Потім використовуйте LINQ для 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.