A view model represents the data that you want to display on your view/page, whether it be used for static text or for input values (like textboxes and dropdown lists) that can be added to the database (or edited). It is something different than your domain model. It is a model for the view.
Let us say that you have an Employee class that represents your employee domain model and it contains the following properties (unique identifier, first name, last name and date created):
public class Employee : IEntity
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime DateCreated { get; set; }
}
View models differ from domain models in that view models only contain the data (represented by properties) that you want to use on your view. For example, lets say that you want to add a new employee record, your view model might look like this:
public class CreateEmployeeViewModel
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
As you can see it only contains two of the properties. These two properties are also in the employee domain model. Why is this you may ask? Id might not be set from the view, it might be auto generated by the Employee table. And DateCreated might also be set in the stored procedure or in the service layer of your application. So Id and DateCreated are not needed in the view model. You might want to display these two properties when you view an employee’s details (an employee that has already been captured) as static text.
When loading the view/page, the create action method in your employee controller will create an instance of this view model, populate any fields if required, and then pass this view model to the view/page:
public class EmployeeController : Controller
{
private readonly IEmployeeService employeeService;
public EmployeeController(IEmployeeService employeeService)
{
this.employeeService = employeeService;
}
public ActionResult Create()
{
CreateEmployeeViewModel model = new CreateEmployeeViewModel();
return View(model);
}
public ActionResult Create(CreateEmployeeViewModel model)
{
// Do what ever needs to be done before adding the employee to the database
}
}
Your view/page might look like this (assuming you are using ASP.NET MVC and the Razor view engine):
@model MyProject.Web.ViewModels.CreateEmployeeViewModel
First Name: | @Html.TextBoxFor(m => m.FirstName, new { maxlength = “50”, size = “50” }) @Html.ValidationMessageFor(m => m.FirstName) |
Last Name: | @Html.TextBoxFor(m => m.LastName, new { maxlength = “50”, size = “50” }) @Html.ValidationMessageFor(m => m.LastName) |
Validation would thus be done only on FirstName and LastName. Using FluentValidation you might have validation like this:
public class CreateEmployeeViewModelValidator : AbstractValidator
{
public CreateEmployeeViewModelValidator()
{
RuleFor(m => m.FirstName)
.NotEmpty()
.WithMessage(“First name required”)
.Length(1, 50)
.WithMessage(“First name must not be greater than 50 characters”);
RuleFor(m => m.LastName)
.NotEmpty()
.WithMessage(“Last name required”)
.Length(1, 50)
.WithMessage(“Last name must not be greater than 50 characters”);
}
}
And with Data Annotations it might look this:
public class CreateEmployeeViewModel : ViewModelBase
{
[Display(Name = “First Name”)]
[Required(ErrorMessage = “First name required”)]
public string FirstName { get; set; }
[Display(Name = “Last Name”)]
[Required(ErrorMessage = “Last name required”)]
public string LastName { get; set; }
}
The key thing to remember is that the view model only represents the data that you want to use, nothing else. You can imagine all the unnecessary code and validation if you have a domain model with 30 properties and you only want to update a single value. Given this scenario you would only have this one value/property in the view model and not all the properties that are in the domain object.
A view model might not only have data from one database table. It can combine data from another table. Take my example above about adding a new employee record. Besides adding just the first and last names you might also want to add the department of the employee. This list of departments will come from your Departments table. So now you have data from the Employees and Departments tables in one view model. You will just then need to add the following two properties to your view model and populate it with data:
public int DepartmentId { get; set; }
public IEnumerable
When editing employee data (an employee that has already been added to the database) it wouldn’t differ much from my example above. Create a view model, call it for example EditEmployeeViewModel. Only have the data that you want to edit in this view model, like first name and last name. Edit the data and click the submit button. I wouldn’t worry too much about the Id field because the Id value will probably been in the URL, for example:
http://www.yourwebsite.com/Employee/Edit/3
Take this Id and pass it through to your repository layer, together with your first name and last name values.
When deleting a record, I normally follow the same path as with the edit view model. I would also have a URL, for example:
http://www.yourwebsite.com/Employee/Delete/3
When the view loads up for the first time I would get the employee’s data from the database using the Id of 3. I would then just display static text on my view/page so that the user can see what employee is being deleted. When the user clicks the Delete button, I would just use the Id value of 3 and pass it to my repository layer. You only need the Id to delete a record from the table.
Another point, you don’t really need a view model for every action. If it is simple data then it would be fine to only use EmployeeViewModel. If it is complex views/pages and they differ from each other then I would suggest you use separate view models for each.
I hope this clears up any confusion that you had about view models and domain models.
View model is a class that represents the data model used in a specific view. We could use this class as a model for a login page:
public class LoginPageVM
{
[Required(ErrorMessage = “Are you really trying to login without entering username?”)]
[DisplayName(“Username/e-mail”)]
public string UserName { get; set; }
[Required(ErrorMessage = “Please enter password:)”)]
[DisplayName(“Password”)]
public string Password { get; set; }
[DisplayName(“Stay logged in when browser is closed”)]
public bool RememberMe { get; set; }
}
Using this view model you can define the view (Razor view engine):
@model CamelTrap.Models.ViewModels.LoginPageVM
@using (Html.BeginForm()) {
@Html.EditorFor(m => m);
}
And actions:
[HttpGet]
public ActionResult LoginPage()
{
return View();
}
[HttpPost]
public ActionResult LoginPage(LoginPageVM model)
{
…code to login user to application…
return View(model);
}
Which produces this result (screen is taken after submitting form, with validation messages):
As you can see, a view model has many roles:
View models documents a view by consisting only fields, that are represented in view.
View models may contain specific validation rules using data annotations or IDataErrorInfo.
View model defines how a view should look (for LabelFor,EditorFor,DisplayFor helpers).
View models can combine values from different database entities.
You can specify easily display templates for view models and reuse them in many places using DisplayFor or EditorFor helpers.
Another example of a view model and its retrieval: We want to display basic user data, his privileges and users name. We create a special view model, which contains only the required fields. We retrieve data from different entities from database, but the view is only aware of the view model class:
public class UserVM {
public int ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public bool IsAdministrator { get; set; }
public string MothersName { get; set; }
}
Retrieval:
var user = db.userRepository.GetUser(id);
var model = new UserVM() {
ID = user.ID,
FirstName = user.FirstName,
LastName = user.LastName,
IsAdministrator = user.Proviledges.IsAdministrator,
MothersName = user.Mother.FirstName + ” ” + user.Mother.LastName
}