AutoMapper中的Map和DynamicMap——高手注重细节,思考和总结
近日在做项目的时候,遇到了个怪问题,关于AutoMapper的细节问题,也是不为一般人所关注的。
本人研究AutoMapper也没有多长时间,而且研究的过程中也写了关于AutoMapper的系列基础教程,但是毕竟AutoMapper是个开源项目,并不是一个简单的系列教程就能解释的清楚的,只能解释个大概,项目实战的时候,遇到的细节问题还得自己私下里再次研究、总结。
首先,我要说明的是,这篇博客的写作顺序是按事情发展的顺序来写的,也就是说,在我想写这篇博客时,问题的根本原因还没找到,但是此时,我回过头来,再来看这个过程中每个问题的解决思路,我想,此时这个细节的问题已经清楚了,也来分享一下。
先来让大家看看我的AutoMapper的大致配置过程:
- 先创建实体类对应的AutoMapper配置类,命名规范是EntityName(实体类名)+Profile,比如PersonProfile,ProvincePerfile等。
public class ProvinceProfile : Profile
{
protected override void Configure()
{
Mapper.Initialize(cfg => cfg.CreateMap<Provinces, ProvinceDto>()
.ForSourceMember(src=>src.UpdatedDate,opt=>opt.Ignore())
.ReverseMap());
}
}
- 再创建一个静态类,取名AutoMapperConfig,然后在他的静态方法中初始化Mapper,并添加所有的配置类,这里我还添加了其他配置类。
public static class AutoMapperWebConfig
{
public static void Configure()
{
Mapper.Reset();
Mapper.Initialize(cfg =>
{
cfg.AddProfile<ProvinceProfile>();
cfg.AddProfile<CityProfile>();
cfg.AddProfile<StationProfile>();
cfg.AddProfile<TerminalDeviceProfile>();//TerminalDeviceProfile依赖ProvinceProfile
cfg.AddProfile<OperatorProfile>();
});
Mapper.AssertConfigurationIsValid();//验证所有的映射配置是否都正常
}
}
- 最后,在项目启动的时候(ASP.Net程序在.asax文件中的Application_Start方法)调用AutoMapperWebConfig.Configure();就可以了。
这一切都感觉这么顺利,但是往往越是顺利的时候,也意味着不顺快来了。接下来,类似下面截图中的错误向我狂轰乱炸。
当我使用在应用层使用Mapper.Map()方法将实体类映射为Dto类时,报错如下:

很明显这是AutoMapper映射错误。
接下来就各种搜索错误,找到了下面一篇博客,原文
ta的解决方案是,如图

看到这里,我很高兴,赶紧改了一下自己的代码,发现果然成功了!但是该博主并没有给出个所以然来。

但是,我不服气,我之前已经创建了两个类之间的映射啊,为啥Mapper.Map()方法不行,我就纳闷了,我非得搞清楚这两者之间的关系不可。
我寻思着,就字面意思来看,一个是“映射”,一个是“动态映射”,会有啥区别呢?
于是各种搜两者之间的区别,去StackOverflow上找到了下面的答案:原链接

这里说,DynamicMap在编译时你不知道源类型的情况下使用,那么,相应地,Map就是在编译时知道源类型的情况下使用。简单的这一句解释并不能让接触AutoMapper时间不长的人有所启示。
而问题就出在,我之前已经创建了映射,所以在编译时应该可以确定源类型的,更何况我这两个类都很简单,不可能是因为数据类型不一致造成的映射失败啊!代码如下:
public class Provinces : Entity
{
public virtual string Code{ get; set; } public virtual string Name{ get; set; }
public virtual string UpdatedBy{ get; set; }
public virtual DateTime? UpdatedDate{ get; set; }
public Provinces(){}
}
public class ProvinceDto:EntityDto
{
public string Code { get; set; }
public string Name { get; set; }
}
于是,还得不到自己想要的答案,就去GitHub上AutoMapper的项目下Open了一个Issue,点击查看我提的Issue,在这里,我得到了我想要的答案。

该回答者给我的答案如上,他猜想我在每个实体类对应的Profile文件中,应该直接使用CreateMap,而不是在Mapper.Initialize中使用CreateMap。按照他的提示,我修改了代码,以后再也没有出现错误。
=============该总结了================
现在再次回头看看这个问题,完全是了然于胸的感觉。因为我在AutoMapperWebconfig静态类的静态方法中已经进行了Mapper.Initialize(),这是AutoMapper的初始化,而在每个实体类对应的Profile类中又使用了一次。尝试着去想一想,第一次将所有的文配置类都初始化到Mapper(暂且先将它理解成一个容器)中,第二次调用Mapper.Initialize()可能会把之前的内容都擦除掉,所以使用Mapper.Map的时候会报错就可以想明白了,而使用DynamicMap,之前在哪里看到过DynamicMap就想当于先CreateMap,再Map,所以,我们之前的配置就可有可无,无关紧要了,因为DynamicMap会把之前的配置擦除掉,所以上面截图中的映射成功了。而至于其他配置类没有出现该错误,该回答者给的答案是”这可能是个意外!“。在这次坎坷曲折的解决问题的过程中,还是学到了很多东西的。在这里,我们也很显然,可以看出博客园那位园友使用DynamicMap成功后而没给出为什么,十有八九也是我这个问题了。
==============总结完毕================
AutoMapper中的Map和DynamicMap——高手注重细节,思考和总结的更多相关文章
- STL 中的map 与 hash_map的理解
可以参考侯捷编著的<STL源码剖析> STL 中的map 与 hash_map的理解 1.STL的map底层是用红黑树存储的,查找时间复杂度是log(n)级别: 2.STL的hash_ma ...
- 【转】hive优化之--控制hive任务中的map数和reduce数
一. 控制hive任务中的map数: 1. 通常情况下,作业会通过input的目录产生一个或者多个map任务. 主要的决定因素有: input的文件总个数,input的文件大小,集群设置 ...
- Map java中的map 如何修改Map中的对应元素
Map java中的map 如何修改Map中的对应元素 Map以按键/数值对的形式存储数据,和数组非常相似,在数组中存在的索引,它们本身也是对象. Map的接口 Map ...
- Java中Set Map List 的区别
java中set map list的区别: 都是集合接口 简要说明 set --其中的值不允许重复,无序的数据结构 list --其中的值允许重复,因为其为有序的数据结构 map--成对的数据结构 ...
- Java中遍历Map集合的四种方法
在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...
- java8中的map和reduce
java8中的map和reduce 标签: java8函数式mapreduce 2014-06-19 19:14 10330人阅读 评论(4) 收藏 举报 分类: java(47) FP(2) ...
- zk框架中利用map类型传值来创建window,并且传值
@Command @NotifyChange("accList") public void clear(@BindingParam("id") String a ...
- python 中的map 详解
python中的map函数应用于每一个可迭代的项,返回的是一个结果list.如果有其他的可迭代参数传进来,map函数则会把每一个参数都以相应的处理函数进行迭代处理.map()函数接收两个参数,一个是函 ...
- 由实现JavaScript中的Map想到的
项目中要用到JavaScript中的Map数据类型,它不像JDK那样有自带的,怎么办?搜了找到一个不错的(http://darkmasky.iteye.com/blog/454749).用这个可以满足 ...
随机推荐
- Python 之WEB框架
wsgi模块实现socketPython web框架: - 自己实现socket 代表:Tornado - 基于wsgi(一种规范,统一接口) 代表: Django 自己开发web框架(基于wsgi) ...
- shellcode流程
shellcode就是汇编的opcode,一般以子函数形式出现: 取得shellcode的方便方式是: 1.写一个函数如: void __stdcall code(LONG &a, LONG ...
- kafka命令
./kafka-topics.sh --zookeeper ip:port --list ./kafka-topics.sh --create --topic test --zookeeper ip: ...
- 【Jquery mobile】动态加载ListView 转
[Jquery mobile]动态加载ListView 分类: Jquery Mobile2011-12-01 09:04 13984人阅读 评论(1) 收藏 举报 jquerylistviewmob ...
- URLConnection 和 HttpClients 发送请求范例
. java.net.URLConnection package test; import java.io.BufferedReader; import java.io.IOException; im ...
- java内存知识
java对内存的分类. (网上资料)程序中用来存放数据的内存分为四块,另有一块用于存放代码 1.堆:存放所有new出来的对象(我们知道java并没有全局变量这个概念,有人是把它单独放在properti ...
- weblogic myeclipse小知识
新建域 http://jingyan.baidu.com/article/f7ff0bfc72904e2e27bb136f.html svn 上down下来一些新项目的时候没法添加到weblogic ...
- Slave failed to initialize relay log info structure from the repository
现象 查看slave 服务状态 show slave status\G; 错误 Last_Errno: 1872 Last_Error: Slave failed to initialize rela ...
- iOS中两个APP之间的跳转和通信
app间的跳转 一:在第一个app首先要做下面这些操作: 1.在info.plist文件中的Information Property List下添加一项:URL types. 2.点开URL type ...
- UICollectionView进阶练习
上一篇中的干货看完,不觉感觉还是有点虚,今天我们来点实的,做了两个小DEMO,源码已放GitHub,主要是针对UICollectionView做了联系.第一个DEMO是针对UICollectionVi ...