使用AutoMapper映射字典

21

给定这些类,我如何映射它们的字典?

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);

将它们中的一个映射,这种情况下是mappedValue,可以正常工作。

将它们中的字典映射到目标对象中最终没有任何条目。

我做错了什么?

2个回答

26
您遇到的问题是因为AutoMapper无法将Dictionary的内容映射过来。您需要考虑这个存储器中存储的是什么,即KeyValuePairs

如果您尝试创建一个KeyValuePair组合的映射器,您很快会发现您不能直接这样做,因为Key属性没有setter

不过,AutoMapper通过允许您使用构造函数来进行映射来解决了这个问题。

/* 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 );

请注意,第二个ConstructUsing使用第一个映射来完成其工作。 - Dave Walker
1
在我的测试用例中,即使没有使用 ConstructUsing,只要添加了 CreateMap<KeyValuePair<string, TestClass>, KeyValuePair<string, TestClassDto>>(),它就开始工作了。 - dodbrian
可能在过去的七年中已经有所改变了 :) - Dave Walker
7
目前版本中,您甚至不需要KeyValuePair映射。实际上,您根本不需要字典->字典映射。只需要TestClass-> TestClassDTO即可。正是显式的字典->字典映射导致了空字典。AutoMapper隐式支持闭合泛型类型映射。(是的,我知道这个问题已经超过七年了 ;)) - oflahero

4

AutoMapper进行了一些更改,现在看起来更像:

CreateMap<Thing, ThingDto>()
     .ReverseMap();
CreateMap<Thing, KeyValuePair<int, ThingDto>>()
     .ConstructUsing((t, ctx) => new KeyValuePair<int, ThingDto>(t.id, ctx.Mapper.Map<ThingDto>(t)));

1
请查看 @oflahero 的评论。 - Lucian Bargaoanu
他的评论以及其他人的评论都没有提到当前版本的ConstructUsing,该版本将两个参数(t,ctx)传递给func,其中t是ThingDto类型,ctx是ResolutionContext。 TMappingExpression ConstructUsing(Func<TSource, ResolutionContext, TDestination> ctor) - Skystrider
1
@LucianBargaoanu,我真希望在浪费一两个小时试图让原始解决方案和评论起作用之前读了Skychan的答案。它非常相关。 - Matt Tew
1
实际上,这比手动映射还糟糕。它是混淆的手动映射。它完全打败了AM的目的。所以,你要么学会正确使用AM,要么就手动完成。 - Lucian Bargaoanu
1
@LucianBargaoanu,请帮助我们了解在这种情况下可以使用AM的其他替代方式。您可能有一个观点,即我们应该只使用手动映射而不是这个,我会记住的。我只是好奇是否您知道另一种正确使用AM来完成此特定情况的方法。映射字典必须是映射的非常普遍的事情,我们都将从中受益并学习到更多。 - Skystrider
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接