Suppose i have a source class:
public class Source { //Several properties that can be mapped to DerivedBase and its subclasses }
And some destination classes:
public class DestinationBase { //Several properties } public class DestinationDerived1 : DestinationBase { //Several properties } public class DestinationDerived2 : DestinationBase { //Several properties }
Then I wish the derived destination classes to inherit the automapper configuration of the baseclass because I do not want to have to repeat it, is there any way to achieve this?
Mapper.CreateMap<Source, DestinationBase>() .ForMember(...) // Many more specific configurations that should not have to be repeated for the derived classes .ForMember(...); Mapper.CreateMap<Source, DestinationDerived1 >() .ForMember(...); Mapper.CreateMap<Source, DestinationDerived2 >() .ForMember(...);
When I write it like this it does not use the base mappings at all, and include doesn't seem to help me.
Edit: This is what I get:
public class Source { public string Test { get; set; } public string Test2 { get; set; } } public class DestinationBase { public string Test3 { get; set; } } public class DestinationDerived1 : DestinationBase { public string Test4 { get; set; } } public class DestinationDerived2 : DestinationBase { public string Test5 { get; set; } }
Mapper.CreateMap<Source, DestinationBase>() .ForMember(d => d.Test3, e => e.MapFrom(s => s.Test)) .Include<Source, DestinationDerived1>() .Include<Source, DestinationDerived2>(); Mapper.CreateMap<Source, DestinationDerived1>() .ForMember(d => d.Test4, e => e.MapFrom(s => s.Test2)); Mapper.CreateMap<Source, DestinationDerived2>() .ForMember(d => d.Test5, e => e.MapFrom(s => s.Test2));
AutoMapper.AutoMapperConfigurationException : Unmapped members were found. Review the types and members below.
Test3
Yes, or you can call CreateMap<ModelClass, ViewModelClass>(). ReverseMap() .
AutoMapper is used whenever there are many data properties for objects, and we need to map them between the object of source class to the object of destination class, Along with the knowledge of data structure and algorithms, a developer is required to have excellent development skills as well.
How do I use AutoMapper? First, you need both a source and destination type to work with. The destination type's design can be influenced by the layer in which it lives, but AutoMapper works best as long as the names of the members match up to the source type's members.
The AutoMapper in C# is a mapper between two objects. That is AutoMapper is an object-object mapper. It maps the properties of two different objects by transforming the input object of one type to the output object of another type.
Include derived mappings into base mapping:
Mapper.CreateMap<Source, DestinationBase>() .ForMember(d => d.Id, op => op.MapFrom(s => s.Id)) // you can remove this .Include<Source, DestinationDerived1>() .Include<Source, DestinationDerived2>(); Mapper.CreateMap<Source, DestinationDerived1>() .ForMember(d => d.Name, op => op.MapFrom(s => s.Text)) .ForMember(d => d.Value2, op => op.MapFrom(s => s.Amount)); Mapper.CreateMap<Source, DestinationDerived2>() .ForMember(d => d.Value, op => op.MapFrom(s => s.Amount));
Usage:
Mapper.AssertConfigurationIsValid(); var s = new Source() { Id = 2, Amount = 10M, Text = "foo" }; var d1 = Mapper.Map<DestinationDerived1>(s); var d2 = Mapper.Map<DestinationDerived2>(s);
See Mapping inheritance on AutoMapper wiki.
UPDATE: Here is full code of classes which works as it should.
public class Source { public int Id { get; set; } public string Text { get; set; } public decimal Amount { get; set; } } public class DestinationBase { public int Id { get; set; } } public class DestinationDerived1 : DestinationBase { public string Name { get; set; } public decimal Value2 { get; set; } } public class DestinationDerived2 : DestinationBase { public decimal Value { get; set; } }
UPDATE (workaround of AutoMapper bug):
public static class Extensions { public static IMappingExpression<Source, TDestination> MapBase<TDestination>( this IMappingExpression<Source, TDestination> mapping) where TDestination: DestinationBase { // all base class mappings goes here return mapping.ForMember(d => d.Test3, e => e.MapFrom(s => s.Test)); } }
And all mappings:
Mapper.CreateMap<Source, DestinationBase>() .Include<Source, DestinationDerived1>() .Include<Source, DestinationDerived2>() .MapBase(); Mapper.CreateMap<Source, DestinationDerived1>() .MapBase() .ForMember(d => d.Test4, e => e.MapFrom(s => s.Test2)); Mapper.CreateMap<Source, DestinationDerived2>() .MapBase() .ForMember(d => d.Test5, e => e.MapFrom(s => s.Test2));
For Automapper 8.0.
Current version has new method IncludeAllDerived
Here's working example:
var config = new MapperConfiguration(cfg => { cfg.CreateMap<Source, DestinationBase>() .ForMember(dest => dest.Test3, opt => opt.MapFrom(src => src.Test)) .IncludeAllDerived(); cfg.CreateMap<Source, DestinationDerived1>() .ForMember(dest => dest.Test4, opt => opt.MapFrom(src => src.Test2)); cfg.CreateMap<Source, DestinationDerived2>() .ForMember(dest => dest.Test5, opt => opt.MapFrom(src => src.Test2)); }); var mapper = config.CreateMapper(); var source = new Source { Test = "SourceTestProperty", Test2 = "SourceTest2Property" }; var d1 = mapper.Map<DestinationDerived1>(source); var d2 = mapper.Map<DestinationDerived2>(source); Assert.Equal("SourceTestProperty", d1.Test3); Assert.Equal("SourceTest2Property", d1.Test4); Assert.Equal("SourceTestProperty", d2.Test3); Assert.Equal("SourceTest2Property", d2.Test5);
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With