AutoMapper

DTO即数据传输对象。

简单来说Model面向业务,我们是通过业务来定义Model的。而DTO是面向界面UI,是通过UI的需求来定义的。通过DTO我们实现了表现层与Model之间的解耦,表现层不引用Model,如果开发过程中我们的模型改变了,而界面没变,我们就只需要改Model而不需要去改表现层中的东西。

一、最简单的用法

有两个类User和UserDto

public class User
    {
         public int Id { get; set; }
         public string Name { get; set; }
         public int Age { get; set; }
     }
 
     public class UserDto
     {
         public string Name { get; set; }
         public int Age { get; set; }
     }

将User转换成UserDto也和简单

Mapper.Initialize(x => x.CreateMap<User, UserDto>());
 User user = new User()
  {
      Id = 1,
       Name = "caoyc",
      Age = 20
   };
var dto = Mapper.Map<UserDto>(user);

 这是一种最简单的使用,AutoMapper会根据字段名称去自动对于,忽略大小写。

二、如果属性名称不同

将UserDto的Name属性改成Name2

Mapper.Initialize(x => 
     x.CreateMap<User, UserDto>()
      .ForMember(d =>d.Name2, opt => {
         opt.MapFrom(s => s.Name);
          })
    );
   User user = new User()
   {
      Id = 1,
      Name = "caoyc",
      Age = 20
   };
 var dto = Mapper.Map<UserDto>(user);

三、使用Profile配置

自定义一个UserProfile类继承Profile,并重写Configure方法

 public class UserProfile : Profile
  {
    protected override void Configure()
      {
         CreateMap<User, UserDto>().ForMember(d => d.Name2, opt =>
            {
                opt.MapFrom(s => s.Name);
           });
       }
}

使用时就这样

Mapper.Initialize(x => x.AddProfile<UserProfile>());
   User user = new User()
  {
     Id = 1,
     Name = "caoyc",
     Age = 20
  };
var dto = Mapper.Map<UserDto>(user);

四、空值替换NullSubstitute

空值替换允许我们将Source对象中的空值在转换为Destination的值的时候,使用指定的值来替换空值。

public class UserProfile : Profile
 {
     protected override void Configure()
     {
               CreateMap<User, UserDto>()
                 .ForMember(d => d.Name2, opt => opt.MapFrom(s => s.Name))
                 .ForMember(d => d.Name2, opt => opt.NullSubstitute("值为空"));              
     }
 }
Mapper.Initialize(x => x.AddProfile<UserProfile>());
   User user = new User()
    {
        Id = 1,
         Age = 20
    };
 var dto = Mapper.Map<UserDto>(user);

结果为:

五、忽略属性Ignore

public class User
 {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
 }
 public class UserDto
 {
        public string Name { get; set; }
        public int Age { get; set; }
}
public class UserProfile : Profile
{
        protected override void Configure()
        {
             CreateMap<User, UserDto>().ForMember("Name", opt => opt.Ignore());
        } 
}

使用

Mapper.Initialize(x => x.AddProfile<UserProfile>());
User user = new User()
{
     Id = 1,
     Name="caoyc",
     Age = 20
};
var dto = Mapper.Map<UserDto>(user);

结果:

六、预设值

如果目标属性多于源属性,可以进行预设值

public class User
{
      public int Id { get; set; }
      public string Name { get; set; }
      public int Age { get; set; }
}
public class UserDto
{
      public string Name { get; set; }
      public int Age { get; set; }
      public string Gender { get; set; }
}
public class UserProfile : Profile
{
      protected override void Configure()
      {
         CreateMap<User, UserDto>();
      }
}

使用

Mapper.Initialize(x => x.AddProfile<UserProfile>());
 User user = new User()
{
      Id = 1,
      Name="caoyc",
      Age = 20
};
UserDto dto = new UserDto() {Gender = "男"};
Mapper.Map(user, dto);

 七、类型转换ITypeConverter

如果数据中Gender存储的int类型,而DTO中Gender是String类型

public class User
{
        public int Gender { get; set; }
 }
public class UserDto
{
       public string Gender { get; set; }
}

类型转换类,需要实现接口ITypeConverter

public class GenderTypeConvertert : ITypeConverter<int, string>
{
      public string Convert(int source, string destination, ResolutionContext context)
      {
          switch (source)
          {
                  case 0:
                       destination = "";
                       break;
                  case 1:
                       destination = "";
                       break;
                  default:
                       destination = "未知";
                       break;
           }
           return destination;
      }
}

配置规则

public class UserProfile : Profile
{
     protected override void Configure()
     {
            CreateMap<User, UserDto>();
            CreateMap<int, string>().ConvertUsing<GenderTypeConvertert>();
            //也可以写这样
            //CreateMap<int, string>().ConvertUsing(new GenderTypeConvertert());
     }
}

使用

Mapper.Initialize(x => x.AddProfile<UserProfile>());
User user0 = new User() { Gender = 0 };
User user1 = new User() { Gender = 1 };
User user2 = new User() { Gender = 2 };
var dto0= Mapper.Map<UserDto>(user0);
var dto1 = Mapper.Map<UserDto>(user1);
var dto2 = Mapper.Map<UserDto>(user2);

Console.WriteLine("dto0:{0}", dto0.Gender);
Console.WriteLine("dto1:{0}", dto1.Gender);
Console.WriteLine("dto2:{0}", dto2.Gender);

结果

八、条件约束Condition

当满足条件时才进行映射字段,例如人类年龄,假设我们现在人类年龄范围为0-200岁(这只是假设),只有满足在这个条件才进行映射

public class User
{
        public int Age { get; set; }
}

public class UserDto
{
        public int Age { get; set; }
}

Profile

public class UserProfile : Profile
{
     protected override void Configure()
     {
          CreateMap<User, UserDto>().ForMember(dest=>dest.Age,opt=>opt.Condition(src=>src.Age>=0 && src.Age<=200));
     }
}

使用代码

Mapper.Initialize(x => x.AddProfile<UserProfile>());
User user0 = new User() { Age = 1 };
User user1 = new User() { Age = 150 };
User user2 = new User() { Age = 201 };
var dto0= Mapper.Map<UserDto>(user0);
var dto1 = Mapper.Map<UserDto>(user1);
var dto2 = Mapper.Map<UserDto>(user2);

Console.WriteLine("dto0:{0}", dto0.Age);
Console.WriteLine("dto1:{0}", dto1.Age);
Console.WriteLine("dto2:{0}", dto2.Age);

输出结果

倘若在项目中真正要用的时候,我觉得还是应该对AutoMapper的方法进行一些整理,最好能够封装一下,这里我通过扩展方法的形式将其封装为AutoMapperHelper,这样以后使用AutoMapper就变的SO EASY了~

using System.Collections;
using System.Collections.Generic;
using System.Data;
using AutoMapper;
namespace Infrastructure.Utility

{
    /// <summary>
    /// AutoMapper扩展帮助类
    /// </summary>
    public static class AutoMapperHelper
    {
        /// <summary>
        ///  类型映射
        /// </summary>
        public static T MapTo<T>(this object obj)
        {
            if (obj == null) return default(T);
            Mapper.CreateMap(obj.GetType(), typeof(T));
            return Mapper.Map<T>(obj);
        }
        /// <summary>
        /// 集合列表类型映射
        /// </summary>
        public static List<TDestination> MapToList<TDestination>(this IEnumerable source)
        {
            foreach (var first in source)
            {
                var type = first.GetType();
                Mapper.CreateMap(type, typeof(TDestination));
                break;
            }
            return Mapper.Map<List<TDestination>>(source);
        }
        /// <summary>
        /// 集合列表类型映射
        /// </summary>
        public static List<TDestination> MapToList<TSource, TDestination>(this IEnumerable<TSource> source)
        {
            //IEnumerable<T> 类型需要创建元素的映射
            Mapper.CreateMap<TSource, TDestination>();
            return Mapper.Map<List<TDestination>>(source);
        }
        /// <summary>
        /// 类型映射
        /// </summary>
        public static TDestination MapTo<TSource, TDestination>(this TSource source, TDestination destination)
            where TSource : class
            where TDestination : class
        {
           if (source == null) return destination;
            Mapper.CreateMap<TSource, TDestination>();
            return Mapper.Map(source, destination);
        }
        /// <summary>
        /// DataReader映射
        /// </summary>
        public static IEnumerable<T> DataReaderMapTo<T>(this IDataReader reader)
        {
            Mapper.Reset();
            Mapper.CreateMap<IDataReader, IEnumerable<T>>();
            return Mapper.Map<IDataReader, IEnumerable<T>>(reader);
        }
    }
}

你可以像下面的栗子这样使用:

//对象映射
ShipInfoModel  shipInfoModel =  ShipInfo.MapTo<ShipInfoModel>();
//列表映射
List< ShipInfoModel > shipInfoModellist = ShipInfoList.MapToList<ShipInfoModel>();
posted @ 2018-08-09 17:36  在西天取经的路上……  阅读(245)  评论(0编辑  收藏  举报