使用自动映射器在两个词典之间进行映射

时间:2020-10-15 21:51:23

标签: .net dictionary automapper .net-core-3.1 automapper-10

我正在尝试用字典在这两个类之间进行映射

class HouseFrom
{
    public IDictionary<string, PersonFrom> Items { get; set; } = new Dictionary<string, PersonFrom>();
}

class PersonFrom
{
    public int Age { get; set; }
}

class HouseTo
{
    public IDictionary<string, PersonTo> People { get; set; } = new Dictionary<string, PersonTo>();
}

class PersonTo
{
    public string Name { get; set; }
    public int Age { get; set; }
}

我通过几种方法使用automapper 10.1.0: 例如(也尝试了其他变体):

cfg.CreateMap<HouseFrom, HouseTo>().ForMember(t => t.People, opt => opt.MapFrom(t => t.Items));
cfg.CreateMap<KeyValuePair<string, PersonFrom>, KeyValuePair<string, PersonTo>>()
                            .ConstructUsing((t, c) => KeyValuePair.Create(t.Key, c.Mapper.Map<PersonTo>(t.Value)))
                            .AfterMap((b, a) => { a.Value.Name = a.Key; Console.WriteLine(a.Value.Name); });
and
cfg.CreateMap<HouseFrom, HouseTo>().ForMember(t => t.People, opt => opt.MapFrom(t => t.Items));
cfg.CreateMap<IDictionary<string, PersonFrom>, IDictionary<string, PersonTo>>()
                                .ConstructUsing((t, c) => t.Select(t => new PersonTo { Age = t.Value.Age, Name = t.Key }).ToDictionary(k => k.Name, v => v));
and
    
cfg.CreateMap<HouseFrom, HouseTo>().ForMember(t => t.People, opt => opt.MapFrom(t => t.Items));
cfg.CreateMap<KeyValuePair<string, PersonFrom>, KeyValuePair<string, PersonTo>>()
                            .ConstructUsing((c, ctx) => KeyValuePair.Create(c.Key, ctx.Mapper.Map<PersonTo>(c)))
                            .ForMember(t => t.Value, opt => opt.Ignore())
                            .ForMember(t => t.Key, opt => opt.Ignore());

但是我要么得到此异常:

Mutating a key collection derived from a dictionary is not allowed.

或该映射不会填充 PersonTo Name 参数,因此为 null

感谢您在此问题上的帮助。

更新: 我尝试了以下映射,但都没有成功:

        new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<HouseFrom, HouseTo>()
                .ForMember(t => t.People, opt => opt.MapFrom(t => t.Items));
            cfg.CreateMap<KeyValuePair<string, PersonFrom>, KeyValuePair<string, PersonTo>>()
                .ConstructUsing((t, c) => KeyValuePair.Create(t.Key, c.Mapper.Map<PersonTo>(t)));
            cfg.CreateMap<KeyValuePair<string, PersonFrom>, PersonTo>()
                .ForMember(src => src.Age, opt => opt.MapFrom(t => t.Value.Age))
                .ForMember(src => src.Name, opt => opt.MapFrom(t => t.Key));
        });
        //Throws : Mutating a key collection derived from a dictionary is not allowed.

        new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<HouseFrom, HouseTo>()
                .ForMember(t => t.People, opt => opt.MapFrom(t => t.Items));
            cfg.CreateMap<PersonFrom, PersonTo>();
            cfg.CreateMap<KeyValuePair<string, PersonFrom>, KeyValuePair<string, PersonTo>>()
                .ConstructUsing((t, c) => KeyValuePair.Create(t.Key, c.Mapper.Map<PersonTo>(t.Value)))
                .AfterMap((b, a) => { a.Value.Name = a.Key; });
        });
        //Return NULL for Name

        new MapperConfiguration(cfg =>
        {
            cfg.CreateMap<HouseFrom, HouseTo>()
                .ForMember(t => t.People, opt => opt.MapFrom(t => t.Items));
            cfg.CreateMap<IDictionary<string, PersonFrom>, IDictionary<string, PersonTo>>()
                .ConstructUsing((t, c) => t.Select(t => new PersonTo { Age = t.Value.Age, Name = t.Key }).ToDictionary(k => k.Name, v => v));
        });
        //Throws : Mutating a key collection derived from a dictionary is not allowed.

解决方案:

            return new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<HouseFrom, HouseTo>()
                    .ForMember(t => t.People, opt => opt.MapFrom(t => t.Items));
                cfg.CreateMap<IDictionary<string, PersonFrom>, IDictionary<string, PersonTo>>()
                    .ConstructUsing((t, c) => t.Select(t => new PersonTo { Age = t.Value.Age, Name = t.Key }).ToDictionary(k => k.Name, v => v))
                    .ForMember(t => t.Keys, opt => opt.Ignore())
                    .ForMember(t => t.Values, opt => opt.Ignore());
            });

1 个答案:

答案 0 :(得分:-1)

您可以尝试这样

  var config = new MapperConfiguration(cfg => {
            cfg.CreateMap<PersonFrom, PersonTo>().ForMember(x => x.Age, o => o.MapFrom(y => y.Age));
            cfg.CreateMap<KeyValuePair<string, PersonFrom>, KeyValuePair<string, PersonTo>>()
            .ConstructUsing(x => new KeyValuePair<string, PersonTo>(x.Key,new PersonTo { Age = x.Value.Age}));
            cfg.CreateMap<HouseFrom, HouseTo>().ForMember(x=>x.People,o=>o.MapFrom(y=>y.Items));
        }); 

        IMapper mapper = config.CreateMapper();

        var testDict = new Dictionary<string, PersonFrom>();
        var testValue = new PersonFrom()
        {
            Age = 100
        };
        var testValue2 = new PersonFrom()
        {
            Age = 200
        };
        testDict.Add("key1", testValue);
        testDict.Add("key2", testValue2);

        var houseFrom = new HouseFrom { Items = testDict };

        var houseTo = mapper.Map<HouseFrom,HouseTo>(houseFrom);

        foreach (var item in houseTo.People)
        {
            Console.WriteLine(item.Key+" "+item.Value.Name +" "+item.Value.Age);
        }