Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should I use a viewmodel here?

So lets say I have two models: Thingy and Status. Thingy has a Status, and Status has many Thingies. It's typical "Object and Object type relationship".

I have a view where I just want the number of thingies in each status. Or basically a list of Status.Name and Status.Thingies.Count. I could do exactly this, but is the "right" thing to do to create a view model in the form:

ThingiesByStatusViewModel
-StatusName
-StatusThingiesCount

and hook it up with something like AutoMapper.

For such a trivial example, it probably doesn't make much of a difference, but it would help me understand better the proper 'separation of concerns'.

like image 887
hometoast Avatar asked Feb 04 '11 15:02

hometoast


3 Answers

Should I use a viewmodel here?

Is this a rhetorical question?

Your view model would look exactly as you propose and it is perfectly adapted to what you are trying to display here:

public class ThingiesByStatusViewModel
{
    public string StatusName { get; set; }
    public int StatusThingiesCount { get; set; }
}

and then your controller would return an IEnumerable<ThingiesByStatusViewModel>. Then in your view you could simply use a display template:

@Html.DisplayForModel()

and the corresponding display template (~/Views/Shared/DisplayTemplates/ThingiesByStatusViewModel.cshtml):

@model AppName.Models.ThingiesByStatusViewModel
<div>
    <span>StatusName: @Model.StatusName</span>
    <span>Number of thingies: @Model.StatusThingiesCount</span>
</div>

Now let's look at the mapping layer. Suppose that we have the following domain:

public class Thingy
{ }

public class Status
{
    public string StatusName { get; set; }
    public IEnumerable<Thingy> Thingies { get; set; }
}

and we have an instance of IEnumerable<Status>.

The mapping definition could look like this:

Mapper
    .CreateMap<Status, ThingiesByStatusViewModel>()
    .ForMember(
        dest => dest.StatusThingiesCount,
        opt => opt.MapFrom(src => src.Thingies.Count())
    );

and finally the controller action would simply be:

public ActionResult Foo()
{
    IEnumerable<Status> statuses = _repository.GetStatuses();
    IEnumerable<ThingiesByStatusViewModel> statusesVM = Mapper.Map<IEnumerable<Status>, IEnumerable<ThingiesByStatusViewModel>>(statuses);
    return View(statusesVM);
}
like image 70
Darin Dimitrov Avatar answered Oct 06 '22 01:10

Darin Dimitrov


I, personally, don't like to send non-trivial types to the view because then the person designing the view might feel obligated to start stuffing business logic into the view, that that's bad news.

In your scenario, I'd add a StatusName property to your view model and enjoy success.

like image 37
JMP Avatar answered Oct 06 '22 01:10

JMP


Yes, you should use VM.

Guess, You have time for some experiments, so try to do it in a proper way. Next time, you will do that much quicker.

If current example is trivial - then it will be easier to get practice session.

Also, In future your application will grow up and you never know when you need to extend it. So implementing it in proper way provide you a good maintainability for future.

like image 28
Budda Avatar answered Oct 06 '22 00:10

Budda