简体   繁体   中英

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

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).

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