Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to map View Model back to Domain Model in a POST action?

Every article found in the Internet on using ViewModels and utilizing Automapper gives the guidelines of the "Controller -> View" direction mapping. You take a domain model along with all Select Lists into one specialized ViewModel and pass it to the view. That's clear and fine.
The view has a form, and eventually we are in the POST action. Here all the Model Binders come to the scene along with [obviously] another View Model which is [obviously] related to the original ViewModel at least in the part of naming conventions for the sake of binding and validation.

How do you map it to your Domain Model?

Let it be an insert action, we could use the same Automapper. But what if it was an update action? We have to retrieve our Domain Entity from the Repository, update it's properties according to the values in the ViewModel and save to the Repository.

ADDENDUM 1 (9th of February 2010): Sometimes, assigning Model's properties is not enough. There should be taken some action against Domain Model according to the values of View Model. I.e., some methods should be called on Domain Model. Probably, there should be a kind of an Application Service layer which stands between Controller and Domain in order to process View Models...


How to organize this code and where to place it to achieve the following goals?

  • keep controllers thin
  • honor SoC practice
  • follow Domain-Driven Design principles
  • be DRY
  • to be continued ...
like image 440
Anthony Serdyukov Avatar asked Feb 05 '10 08:02

Anthony Serdyukov


2 Answers

I use an IBuilder interface and implement it using the ValueInjecter

public interface IBuilder<TEntity, TViewModel> {       TEntity BuildEntity(TViewModel viewModel);       TViewModel BuildViewModel(TEntity entity);       TViewModel RebuildViewModel(TViewModel viewModel);  } 

... (implementation) RebuildViewModel just calls BuildViewModel(BuilEntity(viewModel))

[HttpPost] public ActionResult Update(ViewModel model) {    if(!ModelState.IsValid)     {        return View(builder.RebuildViewModel(model);     }     service.SaveOrUpdate(builder.BuildEntity(model));    return RedirectToAction("Index"); } 

btw I don't write ViewModel I write Input cuz it's much shorter, but that just not really important
hope it helps

Update: I'm using this approach now in the ProDinner ASP.net MVC Demo App, it's called IMapper now, there's also a pdf provided where this approach is explained in detail

like image 106
Omu Avatar answered Sep 28 '22 04:09

Omu


Tools like AutoMapper can be used to update existing object with data from source object. The controller action for updating might look like:

[HttpPost] public ActionResult Update(MyViewModel viewModel) {     MyDataModel dataModel = this.DataRepository.GetMyData(viewModel.Id);     Mapper<MyViewModel, MyDataModel>(viewModel, dataModel);     this.Repostitory.SaveMyData(dataModel);     return View(viewModel); } 

Apart from what is visible in the snippet above:

  • POST data to view model + validation is done in ModelBinder (could be exended with custom bindings)
  • Error handling (i.e. catching data access exception throws by Repository) can be done by [HandleError] filter

Controller action is pretty thin and concerns are separated: mapping issues are addressed in AutoMapper configuration, validation is done by ModelBinder and data access by Repository.

like image 32
PanJanek Avatar answered Sep 28 '22 03:09

PanJanek