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成功后而没给出为什么,十有八九也是我这个问题了。

==================================================总结完毕==================================================================

时间: 2024-10-18 09:02:17

AutoMapper中的Map和DynamicMap——高手注重细节,思考和总结的相关文章

STL 中的map 与 hash_map的理解

可以参考侯捷编著的<STL源码剖析> STL 中的map 与 hash_map的理解 1.STL的map底层是用红黑树存储的,查找时间复杂度是log(n)级别: 2.STL的hash_map底层是用hash表存储的,查询时间复杂度是常数级别: 3.什么时候用map,什么时候用hash_map? 这个要看具体的应用,不一定常数级别的hash_map一定比log(n)级别的map要好,hash_map的hash函数以及解决地址冲突等都要耗时,而且众所周知hash表是以空间效率来换时间效率的,因而h

深度分析如何在Hadoop中控制Map的数量

深度分析如何在Hadoop中控制Map的数量 [email protected] 很多文档中描述,Mapper的数量在默认情况下不可直接控制干预,因为Mapper的数量由输入的大小和个数决定.在默认情况下,最终input 占据了多少block,就应该启动多少个Mapper.如果输入的文件数量巨大,但是每个文件的size都小于HDFS的blockSize,那么会造成 启动的Mapper等于文件的数量(即每个文件都占据了一个block),那么很可能造成启动的Mapper数量超出限制而导致崩溃.这些逻

java中遍历MAP的几种方法

java中遍历MAP的几种方法 Java代码 Map<String,String> map=new HashMap<String,String>();    map.put("username", "qq");    map.put("passWord", "123");    map.put("userID", "1");    map.put("em

hive优化之------控制hive任务中的map数和reduce数

.    控制hive任务中的map数:  1.    通常情况下,作业会通过input的目录产生一个或者多个map任务. 主要的决定因素有: input的文件总个数,input的文件大小,集群设置的文件块大小(目前为128M, 可在hive中通过set dfs.block.size;命令查看到,该参数不能自定义修改): 2.    举例: a)    假设input目录下有1个文件a,大小为780M,那么Hadoop会将该文件a分隔成7个块(6个128m的块和1个12m的块),从而产生7个ma

javascript中使用Map

mis.comm.js.Map = function() { this.elements = new Array(); //获取MAP元素个数 this.size = function() { return this.elements.length; } //推断MAP是否为空 this.isEmpty = function() { return (this.elements.length < 1); } //删除MAP全部元素 this.clear = function() { this.el

list中含有map的排序问题

Map的种类 在Java中,Map的主要作用是存储键值对.由于是根据键得到值,所以不允许键重复.它主要有如下几个类别: HashMap: 最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的.HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致.如果需要同步,可以用Collections的sy

Java中的Map List Set等集合类

Map List Set等集合类: 一.概述 在JAVA的util包中有两个所有集合的父接口Collection和Map,它们的父子关系: +Collection 这个接口extends自 --java.lang.Iterable接口 ├+List(接口 代表有序,可重复的集合.列表) │├ ArreyList     (Class 数组,随机访问,没有同步,线程不安全) │├ Vector        (Class  数组                   同步        线程全) │

由实现JavaScript中的Map想到的

项目中要用到JavaScript中的Map数据类型,它不像JDK那样有自带的,怎么办?搜了找到一个不错的(http://darkmasky.iteye.com/blog/454749).用这个可以满足项目中要求.在找的过程中,发现这么个轻量级的实现.http://www.iteye.com/topic/196610帖子中,二楼myy的回复内容.应该说这个简单地实现可以满足我的一些需求,但它少了size方法. 在这个简单实现的基础上,自己能不能加一个size方法呢?而不地通过封装Array那样的重

JAVA中遍历Map和Set方法,取出map中所有的key

Java遍历Set集合 1.迭代器遍历: Set<String> set = new HashSet<String>(); Iterator<String> it = set.iterator(); while (it.hasNext()) { String str = it.next(); System.out.println(str); } 2.for循环遍历: for (String str : set) { System.out.println(str); }