ViewModel ends up being a copy of Model - where is the benefit?
Asked Answered
M

1

5

Another question I asked on here has opened a can of worms for me. Currently I have development my MVC application, with models representing my data and used scaffolding to generate my ViewControllers from those models. Where the models didn't have the required information in, I was using partial views to show the relevant information. After some reading I now understand ViewModel's to be the better way of doing things. So my understand is that for each view I will have a specific ViewModel that returns the data for that view.

I have two models, one representing an item and the other, the item options of which there may be multiple.

public class Item
{
    public int ItemId { get; set; }
    public bool Active { get; set; }
    public string ItemCode { get; set; }
    public string Name { get; set; }
    public List<ItemOption> ItemOptions { get; set; }
    //...
}

public class ItemOption
{
    public int ItemOptionId { get; set; }
    public string Name { get; set; }
    public string Barcode { get; set; }
    //...
}

Therefore I assume my ItemDetailViewModel will just contain the information I show to the user in the view:

public class ItemDetailViewModel
{
    public bool Active { get; set; }
    public string ItemCode { get; set; }
    public string Name { get; set; }
    public List<ItemOption> ItemOptions { get; set; }
}

Should I be making my ItemOptions list on the ItemDetailViewModel there own list? For example should it be:

public List<ItemOptionsViewModel> ItemOptions { get; set; }

I think I am missing the benefit of the ViewModel. I've read that it's so we can have all the data in one class relevant for that view and therefore we can keep the view strongly typed. However I seem to just be copying my Models into my ViewModels, so not really gaining any benefit.

In addition, my research has lead me to thinkking AutoMapper is the best way forward. Am I correct in saying I just put the following in my start up config:

Mapper.CreateMap<Item, ItemDetailViewModel>()
            .ForMember(x => x.Active, o => o.MapFrom(s => s.Active))
            .ForMember(x => x.ItemCode, o => o.MapFrom(s => s.ItemCode))
            .ForMember(x => x.Name, o => o.MapFrom(s => s.Name));
            .ForMember(x => x.ItemOptions, o => o.MapFrom(s => s.ItemOptions));

If I do this, how does it work for the edit views. If I save them back to the ItemDetailViewModel will it update my database in EF?

Melanymelaphyre answered 29/12, 2013 at 17:55 Comment(3)
In your AutoMapper configuration, you don't need to map each field if they are named the same thing and have the same type in both objects (i.e. Mapper.CreateMap<Item, ItemDetailViewModel>(); will suffice).Nall
As Darin Dimitrov's answer states, there's rarely a one-to-one correspondence of your model's properties and your view model's, but I think some examples might help. Even with the limited details you've given, I can think of some things a view model might add that don't belong in your model: a property HasItemOptions might be useful for data binding. Or the property setter for Name might store invalid names (to be fixed before saving) where the model property setter would immediately throw an exception.Refugia
@Melanymelaphyre What you're doing is pretty bang on. Keep the item options as a property of your ViewModel, but you might want to understand the ASP.Net Wire Format so that you understand how to shuffle a collection between your view and your controller: hanselman.com/blog/…Delectation
E
8

Use a view model when there's a benefit. If your domain model already has the exact same properties and validation rules and error messages corresponding to this particular view as your view model does then it is obvious that you could reuse your domain model and you don't need to declare a view model. But from my experience that's seldom the case. Or if it is the case then you might start asking yourself why your domain models are so coupled to the views. I mean error messages specific to a view should not be part of a domain model.

So as always you should find the right balance. It's common to have a main view model which aggregates (as properties) one or more domain models.

As a side remark in your AutoMapper configuration you don't need to be mapping each property if it has the same name. That's why the framework is called AutoMapper, because it works by convention. All this long mapping code shown in your question is equivalent to a more simple Mapper.CreateMap<Item, ItemDetailViewModel>();.

Easting answered 29/12, 2013 at 18:0 Comment(2)
Thanks, that's clears most of it up. Just two questions though. Should I be making a ItemOptionsDetailViewModel? Also what happens when using AutoMapper with regards to edit/deleting. If I save to the ViewModel, will it reflect the data back to the original models?Melanymelaphyre
Make an ItemOptionsDetailViewModel only if necessary (see my answer). When you update/delete, your controller action takes the view model and you should map it back to the domain model. In this case you should have the inverse mapping with AutoMapper so that this is bi-directional.Easting

© 2022 - 2024 — McMap. All rights reserved.