Преимущества моделей представлений в MVC существуют независимо от используемой системы баз данных (черт, даже если вы ее не используете). В простых ситуациях CRUD объекты вашей бизнес-модели будут очень близко имитировать то, что вы показываете в представлениях, но в любом другом случае, кроме базового CRUD, это не будет иметь место.
Одна из важных вещей - это проблемы бизнес-логики / целостности данных с использованием того же класса для моделирования / персистентности данных, который используется в представлениях. Возьмите ситуацию, когда у вас есть свойство DateTime DateAdded
в вашем пользовательском классе, чтобы указать, когда пользователь был добавлен. Если вы предоставляете форму, которая подключается прямо к вашему UserInfo
классу, вы получаете обработчик действий, который выглядит следующим образом:
[HttpPost]
public ActionResult Edit(UserInfo model) { }
Скорее всего, вы не хотите, чтобы пользователь мог изменять, когда они были добавлены в систему, поэтому ваша первая мысль - не предоставлять поле в форме.
Однако нельзя полагаться на это по двум причинам. Во-первых, значение для DateAdded
будет таким же, как то, что вы получите, если бы вы сделали new DateTime()
, или оно будет null
(в любом случае для этого пользователя будет неверно).
Вторая проблема заключается в том, что пользователи могут подделать это в запросе формы и добавить &DateAdded=<whatever date>
к данным POST, и теперь ваше приложение изменит поле DateAdded в БД на любое введенное пользователем.
Это сделано специально, поскольку механизм привязки модели MVC просматривает данные, отправленные через POST, и пытается автоматически связать их с любыми доступными свойствами в модели. Он не может знать, что свойство, которое было отправлено, не было в исходной форме, и, таким образом, оно все равно будет связывать его с этим свойством.
У ViewModels нет этой проблемы, потому что ваша модель представления должна знать, как преобразовать себя в / из объекта данных, и у нее нет поля DateAdded
для подмены, она имеет только минимальные поля, необходимые для отображения (или получить) это данные.
В вашем точном сценарии я могу с легкостью воспроизвести это с помощью манипуляции строк POST, поскольку ваша модель представления имеет прямой доступ к вашему объекту данных.
Другая проблема с использованием классов данных прямо в представлениях - это когда вы пытаетесь представить свое представление так, чтобы оно не соответствовало тому, как моделируются ваши данные. Например, предположим, у вас есть следующие поля для пользователей:
public DateTime? BannedDate { get; set; }
public DateTime? ActivationDate { get; set; } // Date the account was activated via email link
Теперь, скажем, как администратор, вас интересует состояние всех пользователей, и вы хотите отобразить сообщение о состоянии рядом с каждым пользователем, а также дать различные действия, которые администратор может выполнять в зависимости от статуса этого пользователя. Если вы используете модель данных, код вашего представления будет выглядеть так:
// In status column of the web page's data grid
@if (user.BannedDate != null)
{
<span class="banned">Banned</span>
}
else if (user.ActivationDate != null)
{
<span class="Activated">Activated</span>
}
//.... Do some html to finish other columns in the table
// In the Actions column of the web page's data grid
@if (user.BannedDate != null)
{
// .. Add buttons for banned users
}
else if (user.ActivationDate != null)
{
// .. Add buttons for activated users
}
Это плохо, потому что у вас много бизнес-логики в ваших представлениях (статус пользователя заблокирован всегда имеет приоритет над активированными пользователями, заблокированные пользователи определяются пользователями с датой запрета и т. Д.). Это также намного сложнее.
Вместо этого, лучшее (по крайней мере, imho) решение - это обернуть своих пользователей в ViewModel, у которого есть перечисление для их статуса, и когда вы конвертируете свою модель в модель представления (конструктор модели представления является хорошим местом для выполнения). это) вы можете вставить свою бизнес-логику один раз, чтобы просмотреть все даты и выяснить, какой статус должен иметь пользователь.
Тогда приведенный выше код упрощается как:
// In status column of the web page's data grid
@if (user.Status == UserStatuses.Banned)
{
<span class="banned">Banned</span>
}
else if (user.Status == UserStatuses.Activated)
{
<span class="Activated">Activated</span>
}
//.... Do some html to finish other columns in the table
// In the Actions column of the web page's data grid
@if (user.Status == UserStatuses.Banned)
{
// .. Add buttons for banned users
}
else if (user.Status == UserStatuses.Activated)
{
// .. Add buttons for activated users
}
Что может показаться не таким уж и малым количеством кода в этом простом сценарии, но делает вещи более удобными в обслуживании, когда логика определения статуса для пользователя становится более сложной. Теперь вы можете изменить логику определения статуса пользователя без необходимости изменения вашей модели данных (вам не нужно менять свою модель данных из-за того, как вы просматриваете данные), и это сохраняет определение статуса в одном месте.