Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Designing an MVC repository using ViewModels

I want to create a repository class to separate out my data logic from my controllers. I am using a ViewModel to represent some data that will be filled with data from different tables.

Here are some questions I have:

  1. For a method like GetAll(), do I return an IQueryable<MyViewModel> or IQueryable<Entity>? If I return viewmodels, how do I cope with a GetAll() that pulls thousands of records?
  2. Do I create a constructor for my custom ViewModel class that takes the Entity as a parameter to do the mapping? (I'm still unfamiliar with automapper so just need an understanding on how to do this from a design point of view)

Again, my main concern is a method like GetAll() which would pull many records. If I did a foreach loop to translate each Entity into a ViewModel seems like a lot of overhead. My thought was to put a reference inside the custom ViewModel class to the IQueryable<Entity> to access from the collection, and have the ListViewModel just have indexers or something like that which reference the collection property.

like image 412
Dr. Dorian White Avatar asked Aug 13 '12 22:08

Dr. Dorian White


People also ask

What are ViewModels in MVC?

In ASP.NET MVC, ViewModel is a class that contains the fields which are represented in the strongly-typed view. It is used to pass data from controller to strongly-typed view.

Should I use ViewModels?

Because of their scoping, use ViewModels as implementation details of a screen level state holder. Don't use them as state holders of reusable UI components such as chip groups or forms. Otherwise, you'd get the same ViewModel instance in different usages of the same UI component under the same ViewModelStoreOwner.

What is the difference between ViewModel and model in MVC?

ViewModel in the MVC design pattern is very similar to a "model". The major difference between "Model" and "ViewModel" is that we use a ViewModel only in rendering views. We put all our ViewModel classes in a "ViewModels" named folder, we create this folder.


1 Answers

1) For a method like GetAll(), do I return an IQueryable or IQueryable? If I return viewmodels, how do I cope with a GetAll() that pulls thousands of records?

IQueryable<Entity>. The repository doesn't deal with view models. Think of the repository as something that is defined in a separate class library that doesn't reference your ASP.NET MVC application which is where your view models live. It is the ASP.NET MVC application that references this library.

2) Do I create a constructor for my custom ViewModel class that takes the Entity as a parameter to do the mapping? (I'm still unfamiliar with automapper so just need an understanding on how to do this from a design point of view)

No. Don't create constructors in your view models especially if you want your controller actions to take those view models as action parameters (think of a POST action). The reason for this is that the default model binder will no longer know how to instantiate your view model and you will have to write custom model binders.

So AutoMapper or manually map.

Example with manual mapping which is what you could start with:

public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    IEnumerable<MyViewModel> model = entities.Select(x => new MyViewModel
    {
        Prop1 = x.Prop1,
        Prop2 = x.Prop2,
        ...
    }); 
    return View(model);
}

And once you get sick of writing this code move to AutoMapper:

public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    IEnumerable<MyViewModel> model = Mapper.Map<IEnumerable<Entity>, IEnumerable<MyViewModel>>(entities); 
    return View(model);
}

or if you write a custom action filter that uses the OnActionExecuted event to pull the domain model that was passed to the view, map it to the view model using AutoMapper and substitute the model with the view model for the view, you could further simplify the repetitive code:

[AutoMap(typeof(IEnumerable<Entity>), typeof(IEnumerable<MyViewModel>))]
public ActionResult SomeAction()
{
    IEnumerable<Entity> entities = Repository.GetAll();
    return View(entities);
}

Again, my main concern is a method like GetAll() which would pull many records. If I did a foreach loop to translate each Entity into a ViewModel seems like a lot of overhead.

Don't be concerned about that. Pulling your records will be a magnitude slower than looping and mapping to the view model.

like image 195
Darin Dimitrov Avatar answered Oct 11 '22 12:10

Darin Dimitrov