Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mapping dictionaries with AutoMapper

Tags:

automapper

Given this these classes, how can I map a dictionary of them?

public class TestClass
{
    public string Name { get; set; }
}

public class TestClassDto
{
    public string Name { get; set; }
}


Mapper.CreateMap<TestClass, TestClassDto>();
Mapper.CreateMap<Dictionary<string, TestClass>, 
                  Dictionary<string, TestClassDto>>();

var testDict = new Dictionary<string, TestClass>();
var testValue = new TestClass() {Name = "value1"};
testDict.Add("key1", testValue);

var mappedValue = Mapper.Map<TestClass, TestClassDto>(testValue);

var mappedDict = Mapper.Map<Dictionary<string, TestClass>, 
                            Dictionary<string, TestClassDto>>(testDict);

Mapping one of them, mappedValue in this case, works fine.

Mapping a dictionary of them ends up with no entries in the destination object.

What am I doing worng?

like image 593
rboarman Avatar asked May 13 '11 16:05

rboarman


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.

What is AutoMapper 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.

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.


2 Answers

The problem you are having is because AutoMapper is struggling to map the contents of the Dictionary. You have to think what it is a store of - in this case KeyValuePairs.

If you try create a mapper for the KeyValuePair combination you will quickly work out that you can't directly as the Key property doesn't have a setter.

AutoMapper gets around this though by allowing you to Map using the constructor.

/* Create the map for the base object - be explicit for good readability */
Mapper.CreateMap<TestClass, TestClassDto>()
      .ForMember( x => x.Name, o => o.MapFrom( y => y.Name ) );

/* Create the map using construct using rather than ForMember */
Mapper.CreateMap<KeyValuePair<string, TestClass>, KeyValuePair<string, TestClassDto>>()
      .ConstructUsing( x => new KeyValuePair<string, TestClassDto>( x.Key, 
                                                                    x.Value.MapTo<TestClassDto>() ) );

var testDict = new Dictionary<string, TestClass>();
var testValue = new TestClass()
{
    Name = "value1"
};
testDict.Add( "key1", testValue );

/* Mapped Dict will have your new KeyValuePair in there */
var mappedDict = Mapper.Map<Dictionary<string, TestClass>,
Dictionary<string, TestClassDto>>( testDict );
like image 136
Dave Walker Avatar answered Sep 25 '22 20:09

Dave Walker


AutoMapper has changed a bit so it looks more like:

CreateMap<Thing, ThingDto>()
     .ReverseMap();
CreateMap<Thing, KeyValuePair<int, ThingDto>>()
     .ConstructUsing((t, ctx) => new KeyValuePair<int, ThingDto>(t.id, ctx.Mapper.Map<ThingDto>(t)));
like image 34
Skystrider Avatar answered Sep 26 '22 20:09

Skystrider