简体   繁体   中英

AutoMapper problem mapping Entity to Dictionary<Guid, string>

I'm having a problem with one of my automapping configurations that I can't seem to solve.

I have an entity of type contact and I'm trying to map a list of these to a dictionary. However, the mapping just doesn't do anything. The source dictionary remains empty. Can anyone offer any suggestions?

Below is a simplified version of the Contact type

public class Contact
{
    public Guid Id { get; set ;}
    public string FullName { get; set; }
}

My automapping configuration looks as follows

Mapper.CreateMap<Contact, KeyValuePair<Guid, string>>()
    .ConstructUsing(x => new KeyValuePair<Guid, string>(x.Id, x.FullName));

And my calling code looks as follows

var contacts = ContactRepository.GetAll(); // Returns IList<Contact>
var options = new Dictionary<Guid, string>();
Mapper.Map(contacts, options);

This should work with the following, no Mapper needed...

var dictionary = contacts.ToDictionary(k => k.Id, v => v.FullName);

The documentation is very sketchy on the AutoMapper website. From what I can tell, the second parameter inMapper.Map is used only to determine what type the return value should be, and is not actually modified. This is because it allows you to perform dynamic mapping based on an existing object whose type is only known at runtime instead of hard-coding a type in the generics.

So the problem in your code is that you are not making use of the return value ofMapper.Map , which actually contains the final converted object. Here is a modified version of your code that I've tested and correctly returns the converted objects as you expect.

var contacts = ContactRepository.GetAll();
var options = Mapper.Map(contacts, new Dictionary<Guid, string>());
// options should now contain the mapped version of contacts

Although it would be more efficient to take advantage of the generic version instead of constructing an unnecessary object just to specify the type:

var options = Mapper.Map<List<Contact>, Dictionary<Guid, string>>(contacts);

Here is a working code sample that can be run in LinqPad (an assembly reference to AutoMapper.dll is needed to run the sample.)

Hope this helps!

Another solution in GitHub AutoMapper:

https://github.com/AutoMapper/AutoMapper/issues/51

oakinger[CodePlex] just wrote a small extension method that solves this:

public static class IMappingExpressionExtensions 
{ 
public static IMappingExpression<IDictionary, TDestination> ConvertFromDictionary<TDestination>(this IMappingExpression<IDictionary, TDestination> exp, Func<string, string> propertyNameMapper) 
{ 
foreach (PropertyInfo pi in typeof(Invoice).GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic)) 
{ 
if (!pi.CanWrite || 
pi.GetCustomAttributes(typeof(PersistentAttribute), false).Length == 0) 
{ 
continue; 
} 

string propertyName = pi.Name; 
propertyName = propertyNameMapper(propertyName); 
exp.ForMember(propertyName, cfg => cfg.MapFrom(r => r[propertyName])); 
} 
return exp; 
} 
} 

Usage: 

Mapper.CreateMap<IDictionary, MyType>() 
.ConvertFromDictionary(propName => propName) // map property names to dictionary keys 

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