AutoMapper
Dto与EF实体之间的转换用AutoMapper会变的很方便、很高效,是大多数项目的选择。博主本人的项目也在使用AutoMapper这个组件
好用归好用,但是想要把它用好又是另一事了。AutoMapper需我们去配置映射才可以去进行Map转换,下面有Person类与对应的Dto类
public class Person { public string Name { get; set; } public string Age { get; set; } } public class PersonDto { public string Name { get; set; } public string Age { get; set; } }
按照官方使用方式,我们需要以下几个步骤
//配置映射 Mapper.Initialize(o => { o.CreateMap<Person, PersonDto>(); o.CreateMap<PersonDto, Person>(); }); var p = new Person { Age = "20", Name = "小明" }; //进行转换 var pDto = Mapper.Map<PersonDto>(p);
当然,上面的使用方式没有什么问题,似乎也很简单。但是对于一个项目来说几十成百的表已经是家常便饭,对于种配置方式会不会很蛋疼呢。想象一些一堆的CreateMap就会让人恶心,我也看到现在有一些解决方案,即对映射进行粒化每一个相关的功能或实体创建Profile类,添加到Profile集合中。在程序运行时统一注册。这样也不错,但是还是会去写一堆的Profile类和CreateMap。
使用Atturibute进行配置映射
在abp中看到了使用特性的方式进行配置映射,简单的一行代码就可以解决问题,但是似乎在没有使用abp的项目里并不是那么使用这种方式,所以我就借鉴了这种方法写了一个属于自己的特性
[AutoMapFrom(typeof(Person))]
首先是创建一个类去继承自Attribute,这是很简单的。在实际项目中不一定都是一个实体对应一个dto的情况,还会有一个实体对应多个dto的情况存在,所以toSource应该是一个数组
public class AutoMapAttribute : Attribute { public Type[] ToSource { get; private set; } public AutoMapAttribute(params Type[] toSource) { this.ToSource = toSource; } }
后面的代码就更为简单了,我们拿到DTO的程序集,(视项目程序集名而定) ,然后拿到所有的自定义类型判断其中的type是否有贴上了AutoMapAttribute类,如果有的话,创建它的实例,拿到source,然后进行创建映射。很简单对吧。
public class AutoMapperModule { public static void Init() { //拿到dto程序集 var asm = Assembly.Load("DTO"); //拿到自定义的类型 var types = asm.GetExportedTypes(); //创建映射 Mapper.Initialize(o => { foreach (var type in types) { //判断是否贴上了AutoMapAttribute if (!type.IsDefined(typeof(AutoMapAttribute))) continue; var autoMapper = type.GetCustomAttribute<AutoMapAttribute>(); foreach (var source in autoMapper.ToSource) { o.CreateMap(type, source); o.CreateMap(source, type); } } }); } }
最后我们需要在程序启动时去加载这些配置,一切就大功告成了。
protected void Application_Start() { //初始化AutoMapper AutoMapperModule.Init(); }
Map的转换
官网提供的方式是使用Mapper.Map的方式进行转换,假如有一天出现一个更吊,速度更快的开源组件。这个时候我们的项目已经和AutoMapper产生了严重的依赖导致替换会变的很吃力,而且Mapper.Map这种方式也并不是那么的简洁好用。所以写一个Map是势在必行的
我想要的是方式是在对象上直接点出Map并且使用泛型选择我要转换后的类型,这时候已经想到可以用扩展方法了,是不是很方便呢
public static class AutoMapExtension { public static TDestination MapTo<TDestination>(this object source) { return Mapper.Map<TDestination>(source); } public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination) { return Mapper.Map(source, destination); } }
static void Main(string[] args) { //配置映射 Mapper.Initialize(o => { o.CreateMap<Person, PersonDto>(); o.CreateMap<PersonDto, Person>(); }); var p = new Person { Age = "20", Name = "小明" }; //进行转换 p.MapTo<PersonDto>(); }