Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping domain model to view model via AutoMapper or not

I want to use view model for display insted of domain model. And I want to customise a property for display, how should I do this? And is it a good practice to use AutoMapper for display?

Below is the code sample:

public class BookController : BaseController
    {
        private IBookService bookService;

        public BookController(IBookService bookService)
        {
            this.bookService = bookService;
        }

        public ActionResult Details(int id)
        {
            var book = bookService.GetBookById(id);

            return View(Mapper.Map<BookView>(book));
        }
}

    public class Book 
    {        
        public virtual int Id { get; set; }
        public virtual string Name { get; set; }
    }

    public class BookView
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

If I use another way, I can customise any property, like below:

  public ActionResult Details(int id)
        {
            var book = bookService.GetBookById(id);

            return View(new BookView(book));
        }

    public class BookView
    {
       public BookView(Book book){
         Name = book.Name +" Decorated";
       }
        public int Id { get; set; }
        public string Name { get; set; }
    }

How should I do this? And is it a good practice to use AutoMapper for display?

Update

It seems using automapper in the scenario below is more appropriate. For example, mapping a view model to domain model like below. Any opinions?

  [HttpPost]
    public ActionResult Create(BookView bookView)
    {
        try
        {
            var book = Mapper.Map<Book>(bookView);  //this is wrong

            bookService.SaveOrUpdate(book);

            return RedirectToAction("Index");
        }
        catch
        {
            return View();
        }
    }

Update 2

For complex custom display via view model, I don't want to use automapper to map display logic, assuming automapper can map it. Because it mixes different purposes. For example:

Mapper.CreateMap<Book, BookView>()
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name + " this is for display purpose"));

However, using manual mapping like below seems intuitive.

 public BookView(Book book){
    //mapping here
}

Update 3

Quote from Jimmy Bogard:

I think using AutoMapper because you don’t want to use the “=” operator is a bit lazy. Instead, we use it to flatten and reshape, optimizing for the destination type’s environment. Remember, my original motivation for AutoMapper was:

Enable protecting the domain layer from other layers by mapping to DTOs

Thanks @AndrewWhitaker for the link

like image 762
Pingpong Avatar asked May 13 '13 17:05

Pingpong


People also ask

When should you not use AutoMapper?

If you have to do complex mapping behavior, it might be better to avoid using AutoMapper for that scenario. Reverse mapping can get very complicated very quickly, and unless it's very simple, you can have business logic showing up in mapping configuration.

Is AutoMapper faster than manual mapping?

Inside this article, it discusses performance and it indicates that Automapper is 7 times slower than manual mapping. This test was done on 100,000 records and I must say I was shocked.

Is it good to use AutoMapper?

AutoMapper is a great tool when used for simple conversions. When you start using more complex conversions, AutoMapper can be invaluable. For very simple conversions you could of course write your own conversion method, but why write something that somebody already has written?

What is AutoMapper used for?

AutoMapper is a popular object-to-object mapping library that can be used to map objects belonging to dissimilar types. As an example, you might need to map the DTOs (Data Transfer Objects) in your application to the model objects.


1 Answers

This is a good use case for AutoMapper (I've used it this way extensively on many projects with success). Generally you do not want to expose domain entities to your view (in MVC, this would be exposing your model directly to your view, which is incorrect).

You do not need a 1-1 mapping between domain entity and viewmodel. You can make them look completely different and customize the mapping in your CreateMap<> call. To use your example:

Mapper.CreateMap<Book, BookView>()
    .ForMember(dest => dest.Name, opt => opt.MapFrom(src => src.Name + " Decorated"));

Worst case, you can ditch automapper for complex cases or use a custom type resolver with automapper to get the job done.

In fact, this is how Jimmy Bogard (the author) recommends using AutoMapper. He specifically mentions mapping from domain entities to ASP.NET MVC ViewModels for use with strongly typed views.

Another advantage is that you can unit test your mapping profiles. This way if you end up with a mismatch between ViewModel and Model you'll get a failing unit test.

Updates:

I think the quote you added to your question further supports using AutoMapper for mapping from domain models to ViewModels:

Instead, we use it to flatten and reshape, optimizing for the destination type’s environment.

So in my example you'd definitely be optimizing for the destination type's environment (in this case a view).

Also per the link I reference above you should not be using automapper to map to the domain, only from. With that in mind, you'll have to write some logic to create/update domain entities from what you receive from the View no matter what. Remember that controller actions should not take domain entities directly (you should not trust data that comes directly from the view--let the model determine if a domain entity would be valid or not).

like image 54
Andrew Whitaker Avatar answered Oct 10 '22 11:10

Andrew Whitaker