Я начну с некоторых определений:
- A view-model - это тип, который представляет данные, относящиеся к конкретному отображаемому представлению. Действие контроллера должно создать этот объект и заполнить его загруженными данными, а затем передать его представлению.
- Это лежит в основе разделения проблем в ASP.NET MVC и ASP.NET Core и является общим шаблоном проектирования во всех современных (после 2005 года) средах веб-программирования.
- Сравните это со старым школьным программированием на PHP / CGI / Classic ASP, где вы бы смешали код базы данных с HTML.
- В веб-программировании View-Model, как правило, является ненаблюдаемым, неизменным и эфемерным объектом, который длится только в течение жизни HTTP-запроса. В то время как в настольном программировании (например, WPF, UWP XAML и т. Д.) Модель представления обычно наблюдаема, изменчива и долговечна ).
- A model (отличный от view-model ) или entity class - это объект, который представляет данные из вашей базы данных резервного хранилища. (Не обращайте внимания на тот факт, что Razor использует ключевое слово
@model
для обозначения модели представления).
(Я разочарован и раздражен тем, что большинство учебников начального уровня для ASP.NET MVC и ASP.NET Core по-прежнему знакомят пользователей с анти-паттерном использования типов сущностей Entity Framework в качестве моделей представления. Эти учебники должны научить читателей использовать отдельные модели представлений, чтобы избежать введения читателей по неправильному пути и возможной путаницы, как этот OP. Использование сущностей EF в качестве моделей представлений также приводит к проблемам безопасности, поскольку позволяет злонамеренному пользователю сбросить пароли других пользователей (например) если неадекватная проверка входных запросов (для этого, например, [BindNever]
). Моя точка зрения: просто не .)
Вернуться по теме:
Если это одностороннее представление (т. Е. Вы показываете данные только из вашей базы данных, не позволяя пользователю редактировать эти данные в <form>
), тогда определите новый класс в качестве модели представления и заполните его данные вашей сущности как свойства.
В вашем случае ваше действие контроллера равно QuestionsController::Details
, поэтому я бы получил следующее:
public class DetailsViewModel
{
// One-way members:
[BindNever]
public String PageTitle { get; internal set; }
public Question TheQuestion { get; internal set; }
public List<Answer> TheAnswers { get; internal set; }
// Two-way members:
// (you don't have any forms, so this area is empty)
}
Затем измените действие вашего контроллера, чтобы создать, заполнить и вернуть этот тип модели представления:
public async IActionResult Details(Int32? id)
{
if( id == null ) return this.NotFound();
Question question = await this.db.Questions.SingleOrDefaultAsync( id.Value );
if( question == null ) return this.NotFound();
DetailsViewModel vm = new DetailsViewModel()
{
PageTitle = "Details for " + question.Title,
TheQuestion = question,
TheAnswers = await this.db.Answers.Where( q => a.Question == question ).ToListAsync()
};
return this.View( model: vm );
}
И измените свой вид Razor, чтобы использовать эту модель:
@model DetailsViewModel
<html>
<head>
<title>@Model.PageTitle</title>
</head>
<body>
<h2>Question</h2>
<p>@Model.TheQuestion.QuestionText</p>
<h2>Answers</h2>
@foreach( Answer ans in this.Model.TheAnswers )
{
<h3>Answer @ans.Name</h3>
@foreach( Result result in ans.Results )
{
<h3>@result.Name</h3>
}
}
</body>
</html>
Если вы хотите разрешить пользователям редактировать данные в POST
в <form>
, то вам нужно будет по существу определить новые классы для каждой строки таблицы, которую вы хотите, чтобы пользователи могли редактировать. Но это выходит за рамки вашего первоначального вопроса, но поиск в Интернете «ASP.NET MVC модель привязки» для получения дополнительной информации.