Question

I've come across an interesting question during my development. Right now, I use a database-agnostic unit of work layer to abstract the access of data from the actual database dependencies in my ASP MVC 4 web application.

Each individual database project which implements the unit of work interfaces are aware of my business models (models that go directly to/from the database). I'm not too sure how I feel about this approach, but that's not the question I am going to ask.

Should I be using a solution like AutoMapper to convert my business models to/from domain models - models that are passed to the view and used for any work that shouldn't have access to database fields (i.e., IDs)?

For example, consider inside my BusinessModels project, I have the following classes

BusinessModels
    /UserAccounts/
         User.cs
           - ID
           - Username
           - HashedPassword
           - Salt
         UserSettings.cs
           - IsSubscribedToNewsletter
           - AllowDirectEmails

Would it make any sense to bind these User, and UserSettings models into a single model using AutoMapper like so

MyProject
   /DomainModels/
       User.cs
          - Username
          - HashedPassword
          - Salt
          - IsSubscribedToNewsletter
          - AllowDirectEmails

for the purpose of views?

This question also extends to non-MVC projects but I feel seeing as I am working on an MVC project it would make more sense to ask it in that tag.

TLDR is there any point in mapping business models/entities to view models or does that provide an unnecessary layer of abstraction? And if so, would the Repositories contain business models, or view models (which map automatically to business models under-the-hood)?

Was it helpful?

Solution

You can use view models for two different things:

  • rendering a new view (GET action), passing the view model object as the model for the view
  • receiving data back from the view, in a Post Action (POST action), using the view model as parameter

(I know, the second is arguable. But it's not strange to use the view models for this)

The model for the GET action needs all the properties neccessary to render the View:

  • the values of the entity you're showing/editing
  • extra values needed to render the view (for example SelectLists for drop down lists)

Suppose that you have a User which can belong to one UserGroup.

In this case, if you want to edit the user, the model needs:

  • the User data
  • a list of UserGroups

I'd use a model like this:

public class EditUserModel
{
   public User User {get;set;}
   public SelectList UserGroups {get;set;}
}

As you can see, I directly add the User as a property. But I don't add the list of categories as a property, because I don't need the whole list of categories, with all their properties in the view. Besides, if you unit test the controller you can verify that the SelectList is as expected (that couldn't be done if you created the User Groups list in the view)

But, what if you don't need all the properties of the user in the View? Is it worth removing the User property, and add individual properties for Name, Email, JoinedData, Active... ? I think the anser is NO. Imagine you add/remove or rename some of the User entity properties. If you had individual properties in the view model, you'd have to change them as well, before updating the View. And, if you rely on automatic mapping (auto mapper, value injecter) you would't even realized if you make some mistake.

I also said that the view model can be used for posting back data to the controller. So you could do this:

[HttpPost]
public ActionResult Edit(EditUserModel userModel)

If you do so, the model binder will populate the userModel with the values in the form controls. So you'lll get back a half empty model. In this case, the UserGroups list would be null, and, depending on how many of the User's properties you edit, the User could also have many null/non-initialized properties.

To avoid making errors, in some occasions is advisable to create a different model (and probably auxiliary classes) to make it clear what is expected to be posted to the model.

For example, if you have an action to show the whole user data, but which only allows to change its password, you could create a class with two properties: Password, and PasswordConfirmation.

In this case, the view model for the POST could only have the Password and PasswordConfirmation. And derive a model for the GET which has this inherited properties, and also the list of User Groups and the User.

Why inheriting and not using independent classes? Simply beacuse when you use something like Html.TextBoxFor(m => m.User.Name), the Model Binder will be able to set the Name property of the User property, only if the parameter for the post action has the same structure. I.e. if the view model for the get has this structure:

public ChangePasswordModel
{
   public string Password {get;set;}
   public string PasswordConfirmation {get;set;}
   // extra properties, like the list of user groups, the user data...
}

And the model for the post has this structure:

public PostedChanegPasswordModel
{
   public User User {get;set;}
}

The content of the input rendered by Html.TextBoxFor(m => m.EditedUser.Name) won't be bound to the User.Name of the PostedEditViewModel.

But if you make this:

public EditUserModel : PostedEditUserModel
{
   // extra properties, like the list of user groups
}

the data will be bound without any problem.

In general you have to be careful with the models you use for posting and getting. And I recommend using as many different view models as neccesary.

When to use automatic property mapping to completely new view and different models?

You must have a very strong reason to have different view models. This could be a result of starting the application from outside in (i.e. design first) or because a team is developing the UI before or while the business logie is being implemented.

In this case you can find that the classes for the view models, and the views themselves are already defined, and are quite similart to your entities, but not exactly equal. This is one case when I think it can be good to use mappers.

The other reason to use different classes would be to decouple the interface from the logic. But this usually only happens in the previous case.

OTHER TIPS

Regards viewmodels I treat them like a summary of the data you wish to work with.

So taking from your example, your viewmodel would contain data from both the User and UserSettings classes. Let's say you had a view named UserData.cshtml then I would code it up like so:

public class UserDataViewModel
{
    public string Username { get; set; }
    public bool AllowDirectEmails { get; set; }
    // etc ...
}

public ActionResult UserData()
{
    var viewModel = new UserDataViewModel();

    viewModel.UserName = "Whatever";
    viewModel.AllowDirectEmails = false;

    // Or however you get the data for the user.....

    return View(viewModel) 
}

Hopefully you get the idea. So you are on the right track with merging information from externals classes into one viewmodel class. Bascially tie everything together in the viewmodel class.

I name the viewmodel class the same as the view that it's going to be used for. This can help documentation, as well as make it easier for devs new to the code to follow.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top