AutoMapper 是一个对象-对象映射器,可以将一个对象映射到另一个对象。
官方文档:https://docs.automapper.org/en/latest/
通常在一个应用程序中,我们开发人员会在两个不同的类型对象之间传输数据,通常我们会用DTOs(数据传输对象),View Models(视图模型),或者直接是一些从一个service或者Web API的一些请求或应答对象。一个常见的需要使用数据传输对象的情况是,我们想把属于一个对象的某些属性值赋值给另一个对象的某些属性值,但是问题是,这个两个对象可能并不是完全匹配的,比如,两者之间的属性类型,名称等等,是不一样的,或者我们只是想把一个对象的一部分属性值赋值给另一个对象。
手动映射
首先,让我们来看下之前的处理方式,我们通过以下这个例子来直观感受这种方式,我们创建了以下三个类:
public class Author { public string Name { get; set; } } public class Book { public string Title { get; set; } public Author Author { get; set; } } public class BookViewModel { public string Title { get; set; } public string Author { get; set; } }
为了创建Book对象实例的一个View Model对象实例-BookViewModel对象实例,我们需要写如下代码:
BookViewModel model = new BookViewModel { Title = book.Title, Author = book.Author.Name }
上面的例子相当的直观了,但是问题也随之而来了,我们可以看到在上面的代码中,如果一旦在Book对象里添加了一个额外的字段,而后想在前台页面输出这个字段,那么就需要去在项目里找到每一处有这样转换字段的地方,这是非常繁琐的。另外,BookViewModel.Author是一个string类型的字段,但是Book.Author属性却是Author对象类型的,我们用的解决方法是通过Book.Auther对象来取得Author的Name属性值,然后再赋值给BookViewModel的Author属性,这样看起行的通,但是想一想,如果打算在以后的开发中把Name拆分成两个-FisrtName和LastName,那么,呵呵,我们得去把原来的ViewModel对象也拆分成对应的两个字段,然后在项目中找到所有的转换,然后替换。
那么有什么办法或者工具来帮助我们能够避免这样的情况发生呢?AutoMapper正是符合要求的一款插件。
AutoMapper.Mapper.CreateMap<Book, BookViewModel>();
var model = AutoMapper.Mapper.Map<BookViewModel>(book);
使用AutoMappeer的好处是显而易见的,首先,不再需要我们去对DTO实例的属性一一赋值,
然后无论你在Book对象或者BookViewModel对象里加了一个或者更多的字段,那都不会影响这个段映射的代码,我不再需要去找到每一处转换的地方去更改代码,你的程序会像之前正常运转。
不过,还是有个问题并没有得到很好的解决,这也是在AutoMapper文档上缺失的,为把Book.Athor.Name字段赋值给BookViewModel.Author字段,需要在每一处需要执行映射的代码地方,同时创建一个如下的显示转换申明代码,所以如果有很多处转换的话,那么我们就会写很多重复的这几行代码:
AutoMapper.Mapper.CreateMap<Book, BookViewModel>()
.ForMember(dest => dest.Author,
opts => opts.MapFrom(src => src.Author.Name));
所以我们该如何正确的创建映射呢?方式有很多,我这边说下在ASP.NET MVC的程序里如何处理。
在微软的ASP.NET MVC程序中,它提供了一个Global.asax文件,这个文件里可以放置一些全剧配置,上面对于把Book.Athor.Name字段赋值给BookViewModel.Author字段这个映射配置放置在这个文件里面,那么这段代码只会跑一次但是所有转换的地方都能正确的转换Book.Athor.Name为BookViewModel.Author。当然,Global.asax文件中不建议放很复杂的代码,因为这是ASP.NET程序的入口,一档这个文件里出错,那么整个程序就会over。配置代码可以以这样的形式写,创建一个AutoMapper的配置类:
public static class AutoMapperConfig { public static void RegisterMappings() { AutoMapper.Mapper.CreateMap<Book, BookViewModel>() .ForMember(dest => dest.Author, opts => opts.MapFrom(src => src.Author.Name)); } }
然后再Global文件注册这个类:
protected override void Application_Start(object sender, EventArgs e) { AutoMapperConfig.RegisterMappings(); }
创建映射
所有的映射是有CreateMap方法来完成的:
AutoMapper.Mapper.CreateMap<SourceClass, >();
需要注意的是:这种方式是单向的匹配,即在在创建了上面的映射了之后我们可以在程序里从一个SourceClass实例得到一个DestinationClass类型的对象实例:
var destinationClass= AutoMapper.Mapper.Map<DestinationClass>(sourceClass);
但是如果尝试从DestinationClass映射到一个SourceClass,我们到的是一个错误信息:
var book = AutoMapper.Mapper.Map<Book>(bookViewModel);
幸运的是,AutoMapper已经考虑到这个问题了,它提供了ReverseMap方法:
AutoMapper.Mapper.CreateMap<Book, BookViewModel>().ReverseMap();
使用了这个方式后你就可以从Book创建BookViewModel,同时也可以从BookViewModel创建Book对象实例。
从 9.0 开始 Mapper.Initialize
方法就不可用了。 最新版本的功能请参考 https://www.cnblogs.com/gl1573/p/13098031.html
我用的6.0 直接上代码
首先全局配置一个config 在global 某个对象转化 都写上注释 我这里没写
配置好后直接使用