说到AutoMapper也许你还很陌生,使用它又有什么好处呢?今天我就来为大家介绍一下强大的对象映射框架AutoMapper。它是一个强大的领域对象(DTO)关系映射(Object-Object Mapping)框架,可以它可以构建出松耦合,高内聚的系统,在nop中就使用了这个框架。
一、初识AutoMapper
你原来项目中是不是经常有类似这样的代码:
B b=new B();
b.XXX1=a.XXX1;
b.XXX2=a.XXX2;
...
...
...
return b;
对象b和对象a有很多属性都基本上一样。当把两一个对象转换成另一个对象时要一个属性一个属性的分别赋值,这个过程是很繁琐和痛苦的。你有没有想过如果有一个框架可以允许我们只要配置好相关的映射,框架就自动把一个对象转换成另外的对象,并且相应字段也我们填好值了。
庆幸时,AutoMapper可以为我做到这个。
AutoMapper可以发挥的作用就是根据A的模型和B的模型中的定义,自动将A模型映射为一个全新的B模型。
基于访问性的控制或从模型本身上考虑。对外开放的原则是,尽量降低系统耦合度,否则内部一旦变更外部所有的接口都要跟随发生变更;另外,系统内部的一些数据或方法并不希望外部能看到或调用。类似的考虑很多,只是举个例子。
系统设计的原则是高内聚低耦合,尽量依赖抽象而不依赖于具体。这里感觉automapper就是使数据库实体对一个外部调用实体的转换更简便(不用一个属性一个属性的赋值)。
例 如1:数据库里面有用户信息表,供别的系统调用,提供了数据接口。如果直接暴露了数据库层的表结构的话,会对系统本身产生依赖。具体表现在,假定现在因为 某种需要,为用户信息增加了十个字段的信息,那么,如果不进行类型映射的话,会导致所有基于此用户数据结构的模块集体挂掉(接口约定变更)。而如果使用了 映射的话,我们可以在内部进行转换,保持原有接口不变并提供新的更全面的接口,这是保证系统的可维护性和可迁移性。
例如2:一个Web应用 通过前端收集用户的输入成为Dto,然后将Dto转换成领域模型并持久化到数据库中。相反,当用户请求数据时,我们又需要做相反的工作:将从数据库中查询 出来的领域模型以相反的方式转换成Dto再呈现给用户。使用AutoMapper(一个强大的Object-Object Mapping工具),来实现这个转换。
AutoMapper是什么?
AutoMapper是一个将对象映射到对象的映射工具。对象映射的工作机制是:通过输入一个类型的对象然后将其转换成另一个不同类型的对象并输出。在这里AutoMapper要做的(所擅长的)就是提供一些方便的方法,把那些麻烦累人的工作(指对象转换)从类型转换算法中剔除掉。只要需要转换的类型遵循了AutoMapper制定的规则,那么你基本上就不用再写配置算法来实现两个类型之间转换的工作了,AutoMapper会替你自动完成。
//原文:把工作从如将类型A转换成类型B的映射算法中剔除,如果类型B遵循了AutoMapper制定的规则,那么你基本上就可以以零配置来实现两个类型之间转换的工作了。( What makes AutoMapper interesting is that itprovides some interesting conventions to take the dirty work out of figuringout how to map type A to type B.)
为什么使用AutoMapper?
写类型转换的映射代码实在一件枯燥的事情,而对映射做测试则更乏味。AutoMapper为类型转换提供了非常简单的配置算法,同样也易于测试。
现在一个现实的问题是,“为什么使用对象到对象的映射?”
类似于‘映射转换’这样的情况将会发生在项目中非常多的地方,尽管大部分只会发生在层与层之间的边界,例如表示层与领域层之间,或者服务层与领域层之间。如果层与层之间有相关联的话,那么一层的变化会影响到另一层,因此,对象到对象的映射可以隔离这些层的模型,让每一层的变的更加独立,每一层的变化只会影响到自身。
AutoMapper的GitHub的官方地址:https://github.com/AutoMapper/AutoMapper
AutoMapper是一个基于命名约定的对象->对象映射工具。只要2个对象的属性具有相同名字(或者符合它规定的命名约定),AutoMapper就可以替我们自动在2个对象间进行属性值的映射。如果有不符合约定的属性,或者需要自定义映射行为,就需要我们事先告诉AutoMapper,所以在使用 Map(src,dest)进行映射之前,必须使用 CreateMap() 进行配置。
二、AutoMapper的实际运用
2.1、安装AutoMapper
打开nuget程序包管理器控制台,安装AutoMapper在项目中。在命令行输入以下命令:
PM>Install-Package AutoMapper
2.2、创建两个Model类
public class Category { public int ID { get; set; } public string Name { get; set; } } public class CategoryView { public int ID { get; set; } public string Name { get; set; } public List<Product> Products{get;set;} }
3.3、配置AutoMapper
在Application_Start()加如以下代码使配置对象关系。
Mapper.CreateMap<Category, CategoryView>();
Mapper.CreateMap的第一个参数是源类型,第二个参数是目标类型。上面代码的意思也就是要可以把Category类型的对象转换成CategoryView类型的对象。
注意:上面配置了Mapper.CreateMap,还要调用Mapper.Map才能真正实现对象映射之间的转换,最终返回目标类型的对象。如下:
Mapper.Map<Category, CategoryView>(entity)为了调用方便我们写一个类型Category的扩展方法来封装Mapper.Map调用,这样可以让客户端的调用感受到到AutoMapper的存在。
public static class MappingExtensions { public static CategoryView ToModelView(this Category entity) { return Mapper.Map<Category, CategoryView>(entity); } }
3.4、客户端的调用测试一下AutoMapper
在HomeController中新加一个Action名为TestAutoMapper,里面创建一个对象,然后调用ToModelView。如下:
public ActionResult TestAutoMapper() { var m = new Models.Category(){ ID=1, Name="蓝狐软件"}; var v = m.ToModelView(); return View(); }
打断点调试有下图的结果:
可以看到类Category的对象m调用ToModelView()直接将m中相关的属性赋值到对象v中。这样不用我们写代码new一个CategoryView的对象v并依次从m中取值并给v赋值。这些繁琐的操作AutoMapper都为我们做了,其实AutoMapper默认自动把两对对象中相同名的属性进行赋值,除了个特性,其实我们还可以自定义规则,可以指定哪一列到哪一列,也可以忽略某些列等等。
1、忽略列:
Mapper.CreateMap<AddressModel, Address>() .ForMember(dest => dest.CreatedOnUtc, mo => mo.Ignore()) .ForMember(dest => dest.Country, mo => mo.Ignore()) .ForMember(dest => dest.StateProvince, mo => mo.Ignore());
2、对列进行一些处理:
Mapper.CreateMap<QueuedEmail, QueuedEmailModel>() .ForMember(dest => dest.EmailAccountName, mo => mo.MapFrom(src => src.EmailAccount != null ? src.EmailAccount.FriendlyName : string.Empty)) );