近日在做项目的时候,遇到了个怪问题,关于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——高手注重细节,思考和总结的更多相关文章

  1. STL 中的map 与 hash_map的理解

    可以参考侯捷编著的<STL源码剖析> STL 中的map 与 hash_map的理解 1.STL的map底层是用红黑树存储的,查找时间复杂度是log(n)级别: 2.STL的hash_ma ...

  2. 【转】hive优化之--控制hive任务中的map数和reduce数

    一.    控制hive任务中的map数:  1.    通常情况下,作业会通过input的目录产生一个或者多个map任务. 主要的决定因素有: input的文件总个数,input的文件大小,集群设置 ...

  3. Map java中的map 如何修改Map中的对应元素

    Map java中的map 如何修改Map中的对应元素 Map以按键/数值对的形式存储数据,和数组非常相似,在数组中存在的索引,它们本身也是对象.         Map的接口         Map ...

  4. Java中Set Map List 的区别

    java中set map list的区别: 都是集合接口 简要说明 set --其中的值不允许重复,无序的数据结构 list   --其中的值允许重复,因为其为有序的数据结构 map--成对的数据结构 ...

  5. Java中遍历Map集合的四种方法

    在Java中如何遍历Map对象 How to Iterate Over a Map in Java 在java中遍历Map有不少的方法.我们看一下最常用的方法及其优缺点. 既然java中的所有map都 ...

  6. java8中的map和reduce

    java8中的map和reduce 标签: java8函数式mapreduce 2014-06-19 19:14 10330人阅读 评论(4) 收藏 举报  分类: java(47)  FP(2)  ...

  7. zk框架中利用map类型传值来创建window,并且传值

    @Command @NotifyChange("accList") public void clear(@BindingParam("id") String a ...

  8. python 中的map 详解

    python中的map函数应用于每一个可迭代的项,返回的是一个结果list.如果有其他的可迭代参数传进来,map函数则会把每一个参数都以相应的处理函数进行迭代处理.map()函数接收两个参数,一个是函 ...

  9. 由实现JavaScript中的Map想到的

    项目中要用到JavaScript中的Map数据类型,它不像JDK那样有自带的,怎么办?搜了找到一个不错的(http://darkmasky.iteye.com/blog/454749).用这个可以满足 ...

随机推荐

  1. EAS linux挂载数据盘

    查看数据盘名称 fdisk -l 假设没有挂载的数据盘为/dev/xvdb 格式化数据盘 mkfs.ext3 /dev/xvdb 添加自动挂载 mkdir /data echo '/dev/xvdb ...

  2. signtool.exe not found

    When check the [sign the Xap File] checkbox, build project failed due to signtool.exe not found. Fol ...

  3. Echarts 合并版本

    1) Echarts x轴显示不全 解决办法:x轴加上如下代码. axisLabel:{ interval:0 } 2) tooltip文字没有左对齐 解决办法:tooltip加入如下代码. text ...

  4. Linux命令(2)- mv

    mv 功能:可以用来移动文件或者将文件改名. 格式:mv [选项] 源文件或目录 目标文件或目录 说明:mv命令将文件重命名或将其移至一个新的目录中.第二个参数类型是文件时,mv命令完成文件重命名,此 ...

  5. JVM调优-关于jvm的一些基本概念

    1.数据类型 java体系中,数据类型可分为2类:基本类型和引用类型.基本类型保存变量原始值,即:他代表的值就是数值本身: 而引用类型的变量保存引用值."引用值"代表某个对象的引用 ...

  6. 数据库(表)的逻辑备份与恢复<四>

    数据库(表)的逻辑备份与恢复  介绍 逻辑备份是指使用工具 export 将数据对象的结构和数据导出到文件的过程,逻辑恢复是指当数据库对象被误操作而损坏后使用 工具 import 利用备份的文件把数 ...

  7. 浅谈TCP/IP网络编程中socket的行为

    我认为,想要熟练掌握Linux下的TCP/IP网络编程,至少有三个层面的知识需要熟悉: 1. TCP/IP协议(如连接的建立和终止.重传和确认.滑动窗口和拥塞控制等等) 2. Socket I/O系统 ...

  8. java中throw和throws的区别

    throw和throws的区别: throws 用在方法声明后面,跟的是异常类名 可以跟多个异常类名,用逗号隔开 表示抛出异常,由该方法的调用者来处理 throws表示出现异常的一种可能性,并不一定会 ...

  9. Android(Xamarin)之旅(一)

    Xamarin废话我就不多说了. 就是一款编写Android和IOS应用的IDE,从Visual Studio2010就开始有个这个插件.只要发展什么的,我觉得在这里说还不如自己去百度呢. 入正题: ...

  10. 20145225《Java程序设计》 第8周学习总结

    20145225<Java程序设计> 第八周学习总结 教材学习内容总结 第十五章 通用API 15.1日志 日志API:使用日志的起点是Logger类,要取得Logger类,必须使用Log ...