How to convert DTO to View Model and then back again?

asp.net-mvc, asp.net-mvc-4, asp.net-mvc-viewmodel, entity-framework, repository-pattern

Solution

The long-hand response

[HttpPost]
public ActionResult Create(Admin.Models.Product product) 
{
  if (ModelState.IsValid)
  {
    //COMPILE-ERROR: how to convert to DTO?
    var dtoProduct = new AdminAssembly.Models.Product();
    dtoProduct.Property1 = product.Property1;
    dtoProduct.Property2 = product.Property2;
    //...and so on
    db.Add(dtoProduct);
  }
  return View();
}

While this looks verbose and tedious (and it is) it has to happen eventually, somewhere.

You can hide this mapping either in another class or extension method, or you can use a third party like AutoMapper, as Charlino points out.

As a side note, having two classes with the same name in two different namespaces will eventually get confusing (if not for you, then for the next person who has to maintain your code.) Implement friendlier and more descriptive names wherever possible. For example, put all your view models in a folder called ViewModels, not Models. And append all your view models with ViewModel, or VM. It's also a good convention, imo, to name your view models based on the view that they are for, not so much the domain model that they will be mapped to, as not all view models will map directly to a domain model. Sometimes you'll want parts of more than one domain model, for a single view, and that will blow up your naming convention.

So in this particular case I would suggest changing `Admin.Models` to `Admin.ViewModels` and then rename the view model version of `Product` to CreateViewModel. Your code will be much more readable and will not be littered with namespaces throughout your methods.

All of that would result in a method that would look more like this:

[HttpPost]
public ActionResult Create(CreateViewModel viewModel) 
{
  if (ModelState.IsValid)
  {
    var product = new Product();
    product.Property1 = viewModel.Property1;
    product.Property2 = viewModel.Property2;
    //...and so on
    db.Add(product);
  }
  return View();
}

Problem

I'm using MVC 4 with the repository pattern and unit testing also. I have a typical controller that has simple CRUD functionality. I've separated my View Models from my DTOs and I would like to know the best way to convert between the 2: Models: I have `Admin.Models.Product` which is my view model and `AdminAssembly.Models.Product` which is my DTO. Controller: ``` //repo that handles product operations AdminAssembly.Interfaces.IEntityRepository<AdminAssembly.Models.Product> db; //default constructor public ProductController() { db = new AdminAssembly.Repositories.EntityRepo<AdminAssembly.Models.Product>(new AdminAssembly.Models.EntitiesContext()); } //unit testing constructor public ProductController(AdminAssembly.Interfaces.IEntityRepository<AdminAssembly.Models.Product> context) { db = context; } // // POST: /Product/Create [HttpPost] public ActionResult Create(Admin.Models.Product product) { if (ModelState.IsValid) { //COMPILE-ERROR: how to convert to DTO? db.Add(product); } return View(); } // // GET: /Product/Edit/5 public ActionResult Edit(int id) { //COMPILE-ERROR: how to convert to view model? Admin.Models.Product product = db.GetAll().Where(p => p.ID == id); return View(product); } ``` How do I convert between the 2? Do I reference my DTO assembly in my view model and do something like: (won't this break my unit testing?) ``` //convert to AdminAssembly.Models.Product db.Add(product.ToDTO()); //convert back to Admin.Models.Product via constructor Admin.Models.Product product = Admin.Models.new Product(db.GetAll().Where(p => p.ID == id)); ``` Do I need some sort of object conversion black box? ``` Converter.ToViewProduct(product); ``` Some sort of interface? or something else? Update 1: ``` public static class Product { public static Admin.Models.Product ToView(AdminAssembly.Models.Product dto) { Admin.Models.Product viewProduct = new Admin.Models.Product(); //straight copy viewProduct.Property1 = dto.Property1; viewProduct.Property2 = dto.Property2; return viewProduct; } public static AdminAssembly.Models.Product ToDTO(Admin.Models.Product viewModel) { AdminAssembly.Models.Product dtoProduct = new AdminAssembly.Models.Product(); //straight copy dtoProduct.Property1 = viewModel.Property1; dtoProduct.Property2 = viewModel.Property2; //perhaps a bit of wizza-majig dtoProduct.Property1 = viewModel.Property1 + viewModel.Property2; return dtoProduct; } } ```

Original source

Related problems