Home > Mobile >  Project from a collection to a dictionary
Project from a collection to a dictionary

Time:04-30

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.

  • Related