want to get rid of ViewBag in my views so i've made a little research about viewmodels.
i like the idea of using it for presentation, no questions here.
but i don't realise what is the best way to use viewmodels for update.
first of all, why shouldn't i use my EF entities with [MetadataType(typeof(User_Validation))]?
public ActionResult Edit(User user)
{
...
}
where User is EntityObject.
then, if i however use viewmodels for it there is another question: here people believe that nested viewmodels should be used, but here is another opinion ("They are not wrappers around domain models", he says). Who is right?
also, what is the best way to update an object in action after POST (without using tryupdatemodel, because here and not only, people are against this approach). i've tried to use ApplyCurrentValues but if there is some complicated logic of update with many-to-many relations, for example, i get some huge EF errors. that's why i need to manually set fields of my EntityObject that i get from DB with values that come to action. Smth like this:
public ActionResult Edit(User user)
{
if (ModelState.IsValid)
{
var userToUpdate = usersRepository.Get(user.UserId);
userToUpdate.Field1 = user.Field1;
...
// save
}
...
}
where User is EntityObject with validation class.
so, if i use flat viewmodels to get values from form and AutoMapper to set values to my entityobject will it be the most right way to deal with updates or it can be automatized even more?
You answered yourself in the last paragraph. I am using the exactly same approach in my MVC3 EF Code First project.
Here is the practice I follow:
All entity classes are clubbed under one folder "Entity". You can also opt for a separate library project.
Every entity has a corresponding ViewModel class with a postfix of Model (e.g. for Profile entity there is ProfileModel class).
For nested entities there are corresponding nested ViewModel classes.
AutoMapper is used for Model to Entity and vice versa conversions. Here automapper takes care of the nested entities. In case of complex updates, rather than relying on AutoMapper, I take the matter in my own hands in controller.
Works flawlessly with healthy separation between my domain objects and view models.
Related
In an ASP.NET MVC project we are using AutoMapper to map from domain model to viewmodel - and sometimes also flattening a hierarchy while doing so. This works like a charm and makes the rendering logic of our views very lean and simple.
The confusion starts when we want to go the other way from viewmodel (or postmodel or editmodel) to domain model, especially when updating objects. We can't use automated/two-way mapping because:
we would have to unflat the flattened hierarchy
all properties on the domain model would have to be mutable/have public setters
the changes coming from the view isn't always just flat properties being mapped back to the domain, but sometimes need to call methods like "ChangeManagerForEmployee()" or similar.
This is also described in Jimmy Bogards article: The case for two-way
mapping in AutoMapper, but the solution to this isn't described in detail, only that they go:
From EditModel to CommandMessages – going from the loosely-typed
EditModel to strongly-typed, broken out messages. A single EditModel
might generate a half-dozen messages.
In a similar SO question there is an answer by Mark Seeman where he mentions that
We use abstract mappers and services to map a PostModel to a Domain Object
but the details - the conceptual and technical implementation - is left out.
Our idea right now is to:
Recieve a FormCollection in the controller's action method
Get the original domain model and flatten it to viewModelOriginal and viewModelUpdated
Merging the FormCollection into viewModelUpdated using UpdateModel()
Use some generic helper method to compare viewModelOriginal with viewModelUpdated
Either A) Generate CommandMessages a la Jimmy Bogard or B) Mutate the differences directly into the domain model through properties and methods (maybe mapping the 1-1 properties directly through AutoMapper)
Can someone provide some examples of how they come from FormCollection through editmodel/postmodel to domain model? "CommandMessages" or "abstract mappers and services"?
I use the following pattern:
[HttpPost]
public ActionResult Update(UpdateProductViewModel viewModel)
{
// fetch the domain model that we want to update
Product product = repository.Get(viewModel.Id);
// Use AutoMapper to update only the properties of this domain model
// that are also part of the view model and leave the other properties unchanged
AutoMapper.Map<UpdateProductViewModel, Product>(viewModel, product);
// Pass the domain model with updated properties to the DAL
repository.Update(product);
return RedirectToAction("Success");
}
You might want to consider CQRS(Command Query Responsibility Segregation - I think this might be the concept you were missing), possibly even with Event Sourcing.
It is basically a practice of separating the logic of reading from a data source and writing to a data source, might even mean having different data models for reading and writing.
This might be a good place to start: http://abdullin.com/cqrs/
Option C: Put it all in the controller action. Next, if that gets hairy, decompose into services (abstract mappers) or messages-as-methods (the command message way).
Command message way:
public ActionResult Save(FooSaveModel model) {
MessageBroker.Process(model);
return RedirectToAction("List");
}
And the processor:
public class FooSaveModelProcessor : IMessageHandler<FooSaveModel> {
public void Process(FooSaveModel message) {
// Message handling logic here
}
}
This is really just about moving the "processing" of the form out of the controller action and into individual, specialized handlers.
But, I'd only really go this route if controller actions get hairy. Otherwise, just take the form and do the appropriate updates against the domain models as necessary.
There are some similarities here with what I've been doing. My hierarchy of view models is only somewhat flattened from its domain object equivalents, but I do have to deal with calling explicit service methods on save to do things like adding to child collections, changing important values etc, rather than simply reverse mapping. I also have to compare before and after snapshots.
My save is Ajax posted as JSON to an MVC action and enters that action magically bound back to a view model structure by MVC. I then use AutoMapper to transform the top level view model and its descendants back into its equivalent domain structure. I have defined a number of custom AutoMapper ITypeConverters for those cases where a new child item has been added on the client (I'm using Knockout.js) and I need to call an explicit service method. Something like:
foreach (ChildViewModel childVM in viewModel.Children)
{
ChildDomainObject childDO = domainObject.Children.Where(cdo => cdo.ID.Equals(childVM.ID))).SingleOrDefault();
if (childDO != null)
{
Mapper.Map<ChildViewModel, ChildDomainObject>(childVM, childDO);
}
else
{
MyService.CreateChildDO(someData, domainObject); // Supplying parent
}
}
I do a similar thing for deletes and this process cascades quite nicely down through the whole structure. I guess a flattened structure could be either easier to work with or harder - I have an AbstractDomainViewModel with an ID with which I do the above matching, which helps.
I need to do comparisons before and after updating because my service layer calls trigger validation which can affect other parts of the object graph, and this dictates what JSON I need to return as the Ajax response. I only care about changes which are relevant to the UI, so I transform the saved domain object back to a new view model and then have a helper method to compare the 2 view models, using a combination of manual upfront checks and reflection.
I'm learning as I go, so I'm not familiar with all of the concepts behind EF and MVC3. I have an app where my EF Models === MVC3 Models, but I also have some aggregate ViewModels. I call things like Person dude = Person.Get(id); in Controllers, where Person is an EF model generated from a database, which I extend with my custom methods, such as dude.GetSiblings();
What I want to do now (if you don't tell me that this is a bad idea) is to move the EF code into another assembly, create yet another assembly with new simpler non-entity models that I can feed to my views and somehow (if possible) serialize and move around as JSON.
The problem is I don't know how. If I move my EF models to a different project (like a separate DAL), how would I create second models that map to Ef models? Wouldn't that cause a lot of repetition if I had code like int id {get;set;} string name {get;set} on both the EF model and the MVC3 model? In my ViewModels I simply use the entities directly like class ViewModelX { Person person; List<Post> posts; int something; } - but that is simply a packaged set of entities rather than a model, isn't it?
What about methods like GetSiblings? var list = dude.GetSiblings() in Controller and public List<Person> GetSiblings() { return this.EFPerson.GetSiblings(); } in MVC3 model? I'm getting very confused as to what goes where. When googling around, I really only found advanced and very beginner tutorials - or maybe I just don't know what to look for so I kindly ask for your assistance!
If I move my EF models to a different project (like a separate DAL),
how would I create second models that map to Ef models?
The view models reside inside the ASP.NET MVC application.
Wouldn't that cause a lot of repetition if I had code like int id
{get;set;} string name {get;set} on both the EF model and the MVC3
model?
Yes, it will cause. That's what View Models are intended to do. To contain the data that the view needs to work with. Where does this data come from doesn't really matter. You could use tools such as AutoMapper to automate the mapping between your domain models and view models.
What about methods like GetSiblings? var list = dude.GetSiblings() in
Controller and public List GetSiblings() { return
this.EFPerson.GetSiblings(); } in MVC3 model?
Here's how a typical controller action might look like:
public ActionResult SomeAction(int id)
{
// fetch an instance of the domain model:
var domainModel = DomainLayer.GetSiblings(id);
// map the domain model to a view model (using AutoMapper):
var viewModel = Mapper.Map<DomainModel, ViewModel>(domainModel);
// pass the view model back to the view
return View(viewModel);
}
I am working on a fairly large MVC 3 application, and I'm running into an issue that doesn't smell quite right to me. This question takes a little set up to understand, so here are the premises that I'm currently operating on:
Views should be strongly typed (ViewBag/ViewData should be avoided)
Because the views are strongly typed, view model objects should be created that encapsulate all the data the view needs to display
When we have a need for drop down menus we should have two properties:
A property in the model that stores the selected value of the drop down
A SelectList property in the view model that represents the items in the drop down
The view itself always uses the #Html.DropDownListFor() helper method
We are using Entity Framework 4, and letting it generate entity classes from our already designed database
To avoid duplication and take advantage of LINQ, we are not creating our own separate business/model classes but adding to the partial classes generated by the entity framework
These partial classes that we write are located in the business layer to make everything compile correctly
Most model classes have a shared editor template that can be used in multiple views
Here's where the trouble comes in. The shared editor template's model type is set to the model class. This means that the partial view that makes up the editor template does not have access to the containing view model object where the list of drop down items is stored.
I was able to "solve" this by adding a SelectList property directly to the model class in the business layer instead of keeping it in the view model. But the SelectList class is specific to MVC, which in turn means that my business layer has a dependcy on MVC. That doesn't seem right to me because the BL should be agnostic to the UI.
Has anyone else run into this issue? How should I solve this? It's also possible that one of my premises are wrong.
Everything seems very nice and good design up until this point (which is not surprising as it is that point that is causing you headaches :-)):
Most model classes have a shared editor template that can be used in multiple views
It's view models that should have editor templates and not EF models. And because view models are specific to the requirements of the view you are free to put whatever information you need into them, like in this case the SelectList. So don't simply define a root view model that has your EF models as properties (that's not a view model). Define a view model that is designed to meet the requirements of the particular view. Don't put a single EF class in your view model hierarchy and you will see how much simpler your life will be :-)
And don't worry if you have duplicate properties in your view models. That's what those classes are designed for. Also AutoMapper could greatly simplify the mapping between your models and view models.
You have 2 main solution IMHO:
1. Generate DTOs / Models for your business logic entities
You can use AutoMapper to minimize the copying code.
You will achieve a nice separation between your view and business logic.
This however may be time-consuming for your large application.
2. Use extension methods
Instead of declaring a SelectList property in EF entity partial class and polluting your business logic with view-related code create an extention methods for your EF entites in Web project. You can than move your view-related code to web project from BL and keep type-safety.
Example:
Business Logic assembly
// This is EF entity
public partial class FooTable
{
public long Id { get; set; }
public string Name { get; set; }
}
Web assembly
public static class FooTableExtensions
{
public static SelectList GetSelectList(this IEnumerable<FooTable> fooTables)
{
return new SelectList(); // Create your select list from FooTables here.
}
}
Well, we ended up taking the simple way out. In the business layer we just changed the type to plain old Object. I figured that, regardless of the presentation layer, it will need some sort of list to contain the options available.
I know this isn't super clean as per #Darin and #Jakub, but I don't see our end result being any different this way except that we've avoided having to write and/or set up a whole bunch of mappings between objects.
I am pretty new to MVC and I am looking for a way to design my models.
I have the MVC web site project and another class library that takes care of data access and constructing the business objects.
If I have in that assembly a class named Project that is a business object and I need to display all projects in a view ... should I make another model class Project? In this case the classes will be identical.
Do I gain something from doing a new model class?
I don't like having in views references to objects from another dll ... but i don't like duplicating the code neither.
Did you encounter the same problem?
I usually use a combination of existing and custom classes for models, depending on how closely the views map to the actual classes in the datastore. For pure crud pages, using the data class as the model is perfect. In real world use though you usually end up needing a few other bits of data. I find the easiest way to combine them is something like
// the class from the data store
public class MyDataObject {
public string Property1 {get;set;}
public string Property2 {get;set;}
}
// model class in the MVC Models folder
public class MyDataObjectModel {
public MyDataObject MyDataObject {get;set;}
// list of values to populate a dropdown for Property2
public List<string> Property2Values {get;set;}
// related value fetched from a different data store
public string Property3 {get;set;}
}
I also have quite a few model classes that are just a set of form fields - basically corresponding to action parameters from a particular form rather than anything that actually ends up in the database.
If it is exactly the same project then obviously don't need to duplicate the Project class, just use it as is in the view. But in real life often views have specific requirements and it it a good practice to define view model classes in your MVC application. The controller will then map between the model class and the view model to be passed to the view.
You will likely find differing opinions on this. I will give you mine:
I tend to, by default, reuse the object. If the needs of the view change and it no longer needs most/all of the data in the business object, then I'll create a separate view. I would never change the business object to suit the view itself.
If you need most/all of the information in the business object, and need additional data, then I would create a view that holds a reference to the business object and also has properties for the additional data points you need.
One benefit of reusing the business object is that, depending on the data access technology you are using, you can get reuse out of validation. For isntance, ASP.NET MVC 3 coupled with Entity Framework is nice as they both use the attributes in the System.ComponentModel namespace for validation.
That depends on what you mean by model. In the architecture I typically use, I have my Domain model, which is a collection of classes in a separate class library. I use DataAnnotations and built in validation to automatically validate my model when saving.
Then there is the View model, which I place in my MVC project. View models only have the information relevant to the view. I use data annotations here as well since MVC will automatically use them for my validation.
The reason for splitting the model this way is that you don't always use every piece of your domain model in a view. That means you either have to rebuild the data on the backend or you have to stash it in hidden fields. Neither is something I like,.
I'm currently in the process of converting some small personal web sites from WebForms to MVC. With the existing sites, the database schema is solid but I had never really taken the time to build proper data/business models/layers. The aspx pages all talked to the database directly using a variety of Views and Stored Procedures that were created as needed for convenience. With MVC, I'm now trying to "do it right" as they say and use things like LINQ to SQL and/or the Entity Framework to build a proper data model or models for the application.
My question revolves around what goals I should have for building data models. I've read various pattern related articles and I realize that ultimately the answer is likely going to depend on the characteristics of my data. But generally should I attempt to build bigger models that encompass as much of the database as possible so that there's only one way to interact with a given set of tables? Or should I build smaller custom models for each MVC View that only contain the data and access that View will need?
Or should I build smaller custom models for each MVC View that only contain the data and access that View will need?
This would probably be better.
Do not forget, you can stick your models in hierarchies, so common properties, like ids, names, preferences can be present in each model.
Fat expanded models could be better for enterprise application, where framework automatically does lot of stuff based on preloaded user preferences, user roles, access rights etc. For a small personal project would probably be better to try to keep your models small and clean. It is also a protection. By not putting unnecessary data into a model you ensure your view will not by mistake display wrong entries or submitting a form would not by mistake overwrite some other data.
I would go for the model representing the actual data logic within your current system and have your controllers return the piece of the model which the view needs such as:
Controller:
public ActionResult index()
{
var ListOfObjects = DataHelper.GetAll();
ViewData.Add(ListOfObjects);
return View();
}
public ActionResult ViewObject(int id)
{
var Object= DataHelper.GetObject();
ViewData.Add(Object);
return View();
}
public ActionResult ViewObjectChild(int Objectid, int ChildId)
{
var Child= DataHelper.GetChildObject(Objectid, ChildId);
ViewData.Add(Child);
return View();
}
On the view
/
<% var myListOfObjects = ViewData.Get<IList<Object>>(); %>
/ViewObject/1/
<% var myobject= ViewData.Get<Object>(); %>
/ViewChild/1/1/
<% var myChild = ViewData.Get<Child>(); %>
Note I have used MVC Contrib typed functions I highly recommend these.
Generally, you would have one comprehensive domain model for the database. You can use (modify/add/remove/etc.) the domain model in your service layer or the controller if it is a small app.
However, for your views, you can use presentation objects to make the views easier to maintain. These are sometimes also called DTO or view model objects. Basically what you do is create an object that contains all the data from the model that is necessary for the view to be populated.
For example:
Your model may include:
public class Car()
{
public string Model;
}
public class Driver()
{
public string Name;
}
You want the view to output the name and model of the car and you would have to pass both the Car and Driver model objects the view.
Rather than sending the two model objects directly from the controller to the view, you can create an object which contains just the data you need:
public class CarAndDriverViewModel()
{
public string CarMake;
public string DriverName;
}
You would populate this object from the domain data and pass that to the view. And the view would be:
model.DriverName + ": " + model.CarMake
Now you don't have to worry about lazy loading issues or complicated view logic to deal with model peculiarities. It's more work to create these view model objects but they really help keep the view clean and provides an easy way to do formatting before sending data to the view.
There are projects and conventions you can use to help automate the creation of the view models, if you want to look into them. AutoMapper is an example.