Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use AutoMapper to map destination object with a child object in the source object?

I have the source and destination objects like this:

class ProductWithCategories // Source class
{
    public Product Product { get; set; } // Product is an EF entity class
    public IEnumerable<Category> Categories { get; set; }
}

class ProductViewModel // Dest class
{
    public int Id { get; set; }
    // Other properties with the same name as Product class

    public IEnumerable<CategoryViewModel> Categories { get; set; }
}

So, my need is to map the values of source.Product into dest, and then source.Categories into dest.Categories. Is it possible with AutoMapper?

I have tried this and I was not surprised when it failed:

        config.CreateMap<ProductWithCategories, ProductViewModel>()
            .ForMember(q => q, option => option.MapFrom(q => q.Product))
            .ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories));

Here is the exception I received:

[AutoMapperConfigurationException: Custom configuration for members is only supported for top-level individual members on a type.]

like image 629
Luke Vo Avatar asked Feb 23 '16 08:02

Luke Vo


People also ask

Can AutoMapper map collections?

Polymorphic element types in collectionsAutoMapper supports polymorphic arrays and collections, such that derived source/destination types are used if found.

How does AutoMapper work in C#?

AutoMapper in C# is a library used to map data from one object to another. It acts as a mapper between two objects and transforms one object type into another. It converts the input object of one type to the output object of another type until the latter type follows or maintains the conventions of AutoMapper.

Does AutoMapper map private properties?

By default, AutoMapper only recognizes public members. It can map to private setters, but will skip internal/private methods and properties if the entire property is private/internal.

When should I use AutoMapper?

Use AutoMapper to eliminate the need to write tedious boilerplate code when mapping objects in your application. AutoMapper is a popular object-to-object mapping library that can be used to map objects belonging to dissimilar types.


2 Answers

After some discussion with OP, it turns out his main need is to quickly map a child/nested object inside the source object to the flattened destination object. He does not want to write a mapping for every property of the destination.

Here is a way to achieve this:

  • Define a mapping Product -> ProductViewModel used to flatten the members of Product
  • Define a mapping Category to CategoryViewModel
  • Define a mapping ProductWithCategories -> ProductViewModel that maps the categories, and then in the aftermap, map the Product:

    config.CreateMap<ProductWithCategories, ProductViewModel>() .ForMember(q => q.Id, option => option.Ignore()) // flattened in AfterMap .ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories)) .AfterMap((src, dst) => Mapper.Map(src.Product, dst));

like image 159
Georg Patscheider Avatar answered Oct 05 '22 03:10

Georg Patscheider


Using recent versions of AutoMapper, you can do something like the following:

config.CreateMap<Product, ProductViewModel>()
      .ForMember(q => q.Categories, option => option.Ignore());

config.CreateMap<ProductWithCategories, ProductViewModel>()
      .ConstructUsing(s => AutoMapper.Mapper.Map<ProductViewModel>(s.Product))
      .ForMember(q => q.Categories, option => option.MapFrom(q => q.Categories))
      .ForAllOtherMembers(o => o.Ignore();

ConstructUsing() is used to generate and populate the base class from the nested child[ren] of the source. If you have more than one such nested child, you would need to make several mapping calls to map each of them successively onto the instance generated by the first Map() call. The .ForAllOtherMembers() is relatively recent (if you don't have it, get a newer version of AutoMapper.) Unfortunately it's slightly unsafe as if you add destination members which will need mapping but forget to update the map, configuration validation will not catch it.

like image 43
Cliff Hudson Avatar answered Oct 05 '22 03:10

Cliff Hudson