Stian
Stian

Reputation: 1602

Can't convert from model to viewmodel, using AutoMapper

I'm sure this is dead simple, but I need help ... I'm trying to display a single product in a view, and have this query:

var Product = await (from p in _context.Products
                        where p.Id == id
                        select p).FirstOrDefaultAsync();

Then I try to map the result to my viewmodel and return it to the view:

var VMProduct = _mapper.Map<ViewModelProduct, Product>(Product);
return View(VMProduct);

However, I get a build error on the mapping:

"Error CS1503 Argument 1: cannot convert from 'MyStore.Models.Product' to MyStore.Models.ViewModels.ViewModelProduct'"

This is my entity model,

public class Product
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Info { get; set; }
    public decimal Price { get; set; }
    public List<ProductInCategory> InCategories { get; set; }
}

and this is my viewmodel

public class ViewModelProduct
{
    public int Id { get; set; }
    public string Title { get; set; }
    public string Info { get; set; }
    public decimal Price { get; set; }
    public int SortOrder { get; set; }
    public IEnumerable<ViewModelCategoryWithTitle> Categories { get; set; }

    public ViewModelProduct(ProductInCategory pic)
    {
        Id = pic.Product.Id;
        Title = pic.Product.Title;
        Price = pic.Product.Price;
        Info = pic.Product.Info;
        SortOrder = pic.SortOrder;
    }

    public ViewModelProduct() { }
}

This is my mapping profile:

CreateMap<Product, ViewModelProduct>();
CreateMap<ViewModelProduct, Product>();

Edit:

After changing

var VMProduct = _mapper.Map<ViewModelProduct, Product>(Product);

to

var VMProduct = _mapper.Map<Product, ViewModelProduct>(Product);

and adding Mapper.AssertConfigurationIsValid();, I get one step further, and am informed that SortOrder, Categories and InCategories are unmapped.

I'm reluctant to change my viewmodel (too much). Can I make the mapping work with the current viewmodel?

Edit 2:

Apparently, now it works. The unmapped properties are still unmapped, but when I removed Mapper.AssertConfigurationIsValid();, the view rendered just fine.

Upvotes: 1

Views: 3175

Answers (1)

Georg Patscheider
Georg Patscheider

Reputation: 9463

Note that you can define for each member how it should be mapped. This is necessary if the destination member has a different name than the source member. If source and destination have different (complex) types, add an additional mapping config between these types.

If the member is not mapped, but set somewhere else (e.g. in the controller), ignore it to prevent an error when checking the configuration with Mapper.AssertConfigurationIsValid().

CreateMap<Product, ViewModelProduct>()
    // other members will be mapped by convention, because they have the same name
    .ForMember(vm => vm.SortOrder, o => o.Ignore()) // to be set in controller
    .ForMember(vm => vm.Categories, o => o.MapFrom(src => src.InCategories));

// needed to resolve InCategories -> Categories
CreateMap<ViewModelCategoryWithTitle, ProductInCategory>();

Also, most of the time it is sufficient to tell Automapper just the destination type you want, and let it resolve which mapping to apply:

var VMProduct = _mapper.Map<ViewModelProduct>(Product);

Upvotes: 3

Related Questions