让AutoMapper更好用

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>();
        }
posted @ 2016-11-08 17:36  liangshiwei  阅读(1158)  评论(0编辑  收藏  举报