Дві моделі в одному вигляді в 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.