简体   繁体   中英

ViewModels and domain models in ASP.NET MVC

I'm developing an ASP.NET MVC application and I came to a pretty awkward situation.

I have a page where a user can search some items (say, students) by some criteria. I used to pass a collection of students to my view, but then I've added some settings to search so I've decided to create the ViewModel as follows

public class SearchViewModel
{
    public string SearchString { get; set; }
    public bool IsCaseSensitive { get; set; }
    ...
    //other parameters
    ...
    public IEnumerable<Student> Students { get; set; }
}

Then I've thought of the situation when I have to add some additional information to each student, which isn't stored in the database and is generated on controller. My first thought was quite an idiotic - I've added an additional array to save it in the ViewModel like this:

public class SearchViewModel
{
    public string SearchString { get; set; }
    public bool IsCaseSensitive { get; set; }
    ...
    //other parameters
    ...
    public IEnumerable<Student> Students { get; set; }
    public IEnumerable<int> someData { get; set; }
}

So that to get the data, the client code would have to get the students position in the array and then go to the corresponding position in the someData array.

I didn't like that idea very much so I've changed my model to consist of search parameters + an additional model to hold both student object and their data.

public class SearchViewModel
{
    public string SearchString { get; set; }
    public bool IsCaseSensitive { get; set; }
    ...
    //other parameters
    ...
    public IEnumerable<StudentViewModel> StudentModels { get; set; }
}

public class StudentViewModel
{
    public Student Student { get; set; }
    public int someData { get; set; }
}
  1. Is it a fine idea to create such 'helper' models as StudentViewModel? I would probably not use StudentViewModel anywhere but inside the SearchViewModel. Given the SearchViewModel is a kind of 'help' model on itself, creating another model to use only inside the SearchViewModel seems a bit strange. Is it so?

  2. As far as I've found out, a ViewModel should never contain a domain model. Should I divide Student property into smaller properties? For instance, like this:

     public class StudentViewModel { public string Name { get; set; } public int GroupId { get; set; } public int someData { get; set; } } 
  3. In general, as I've understood, a ViewModel should consist only of primitives and their collections (and, probably, other ViewModels as in the first question). Is it correct?

I do not pretend that this inviolable truth. But in my opinion:

  1. Very often view model is created only for one view.
  2. Using domain/data models in views it is normally (if it makes the development process easier/faster/more clear). In your case I would not be used Student class in ViewModel.
  3. ViewModel should contains all data that you need for building view (primitives and not primitives). But if you can make the view model easier and more clear by doing some work in the controller then it should be done.
  1. Is it a fine idea to create such 'helper' models as StudentViewModel?

I believe it is. Your view 'consists' of a list of 'student views'. Viewmodels exist only to serve your views with data that is structured in an optimal way so that the necessary logic in the view is as minimal as possible.

  1. As far as I've found out, a ViewModel should never contain a domain model.

I would advise against using your entities in views, especially when dealing with forms or other ways of data entry. In this case, it's often interesting to create a special "Form model" that contains only the properties you want your user to submit. This also allows you to write validation logic for this specific form. Think of it as a model that serves your form, similarly to how a view model serves your view. Use AutoMapper to fill up these form models to make your life easier.

However, in some scenarios I find it acceptable to use entities in your views: when you use EF and lazy loading, you can use entities when displaying data to profit from the lazy loading mechanism. Only the data you display will get loaded from the database. However, since it is almost always known beforehand which data you will need, there are usually better data loading strategies. Lazy loading is handy during development when lots of changes are happening (loading & showing additional data is fast & easy to implement without having to change much code), but is usually the first thing to tackle during performance reviews.

  1. Should I divide Student property into smaller properties? In general, as I've understood, a ViewModel should consist only of primitives and their collections (and, probably, other ViewModels as in the first question). Is it correct?

I disagree. You designed your domain to represent your business objects, why would you throw that away again in your viewmodels? Always consider the future possibility that your domain models will need to be extended with extra properties and what you can do today to reduce the cost of such changes. If you want to separate your domain layer from your presentation layer, introduce a DTO layer that contains the same objects. On these objects, you can apply data annotations and other stuff that is only applicable in the presentation layer. Filling the DTO's from the domain objects can be done swiftly with AutoMapper. However, be careful not to write your business logic on/with these DTO's.

This is my 2 cents.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM