I am trying to use AutoMapper to convert a collection on an entity to a dictionary. This works when I use the Map function, but it is throwing an exception when I use the queryable extension ProjectTo.
I've created a reproducible example below (usually the ProjectTo would be applied to an EF Core queryable, but in this example, I have just created the Queryable from a list - the resulting exceptions are the same).
using AutoMapper;
using AutoMapper.QueryableExtensions;
var cfg = new MapperConfiguration(config =>
{
config.CreateMap<ParentItem, ParentItemDTO>()
.ForMember(d => d.ChildItems,
o => o.MapFrom(src => src.ChildItems.ToDictionary(key => key.ChildId, value => value)));
config.CreateMap<ChildItem, ChildItemDTO>();
// I have tried adding this and it does not resolve it - throws a different exception
//config.CreateMap<KeyValuePair<string, ChildItem>, KeyValuePair<string, ChildItemDTO>>();
});
var mapper = new Mapper(cfg);
var parent = new ParentItem
{
ParentId = "1",
ChildItems = new List<ChildItem>() {
new ChildItem() { ChildId = "1", Name = "Child 1" },
new ChildItem() { ChildId = "2", Name = "Child 2" }
}
};
var singleResult = mapper.Map<ParentItem, ParentItemDTO>(parent);
var parentQueryable = (new List<ParentItem>() { parent }).AsQueryable();
// This line fails
var projectionResult = parentQueryable.ProjectTo<ParentItemDTO>(mapper.ConfigurationProvider);
public class ParentItem
{
public string ParentId { get; set; }
public List<ChildItem> ChildItems { get; set; }
}
public class ChildItem
{
public string ChildId { get; set; }
public string Name { get; set; }
}
public class ParentItemDTO
{
public string ParentId { get; set; }
public Dictionary<string, ChildItemDTO> ChildItems { get; set; }
}
public class ChildItemDTO
{
public string ChildId { get; set; }
public string Name { get; set; }
}
This successfully works for the single result, but when it hits the ProjectTo line, it will throw the following exception:
System.InvalidOperationException
HResult=0x80131509
Message=Missing map from System.Collections.Generic.KeyValuePair`2[System.String,ChildItem] to System.Collections.Generic.KeyValuePair`2[System.String,ChildItemDTO]. Create using CreateMap<KeyValuePair`2, KeyValuePair`2>.
I have tried adding a KeyValuePair mapping (commented out in the code above), but then it will just throw a different exception:
System.ArgumentException: 'Argument types do not match'
Does anyone know if it's possible to use ProjectTo to map from a collection member to a dictionary member like this? Is there something wrong with my approach, or is this a bug/limitation with AutoMapper?
I am using AutoMapper 11.0.1 and .Net 6.
CodePudding user response:
CreateMap<ChildItem, KeyValuePair<string, ChildItemDTO>>.ConvertUsing(c => new KeyValuePair<string, ChildItemDTO>(c.ChildId, new ChildItemDTO() { ChildId = c.ChildId, Name = c.Description }))
works with the MyGet build. For your version, try a map to Dictionary
.