ASP.NET Core 中的对象映射之 AutoMapper

实践是知识的母亲,知识是生活的明灯。这篇文章主要讲述ASP.NET Core 中的对象映射之 AutoMapper相关的知识,希望能为你提供帮助。

目录

  • AutoMapper 简介
  • AutoMapper 使用
    • 初始化
    • Profile设置
    • 扁平化映射
    • 集合映射
    • 投影
    • 条件映射
    • 值转换
    • 设置转换前后行为
    • 配置验证及设置
    • 反向映射
    • 自定义转换器
    • 自定义解析器
  • 参考

AutoMapper 简介AutoMapper是一个对象映射器,它可以将一种类型的对象转换为另一种类型的对象。
【ASP.NET Core 中的对象映射之 AutoMapper】它提供了映射规则及操作方法,使我们不用过多配置就可以映射两个类, 可以帮我们免于编写无聊的映射代码. 在代码层与层之间隔离模型model上非常有用.
AutoMapper 使用 初始化创建两个简单的类用于测试:
public class UserEntity { public int Id { get; set; } public string Name { get; set; } }public class UserDTO { public int Id { get; set; } public string Name { get; set; } }

AutoMapper可以使用静态类和实例方法来创建映射.
  • 静态类方式
    Mapper.Initialize(cfg => cfg.CreateMap< UserEntity, UserDTO> ()); var userDTO = Mapper.Map< UserDTO> (user);

  • 实例方式
    var config = new MapperConfiguration(cfg => cfg.CreateMap< UserEntity, UserDTO> ()); var mapper = config.CreateMapper(); var userDTO = mapper.Map< UserDTO> (user);

  • 依赖注入
    使用扩展 AutoMapper.Extensions.Microsoft.DependencyInjection 来实现AutoMapper的依赖注入. 本质是注册一个MapperConfiguration的单例和IMapper的scope实例, 通过程序集扫描添加AutoMapper的相关配置和映射.
    IServiceCollection services = new ServiceCollection(); services.AddAutoMapper(); var provider = services.BuildServiceProvider(); using (var scope = provider.CreateScope()) { var mapper = scope.ServiceProvider.GetService< IMapper> (); var userDTO = mapper.Map< UserDTO> (user); }

Profile设置可以使用Profie配置来实现映射关系, 然后通过AddProfile添加.
public class UserProfile : Profile { public UserProfile() { CreateMap< UserEntity, UserDTO> (); } }var config = new MapperConfiguration(cfg => cfg.AddProfile< UserProfile> ());

扁平化映射AutoMapper支持扁平化映射, 它会根据Pascal命名方式分割目标字段为单个单词, 可自动映射属性名+内嵌属性名. 如下例AutoMapper自动映射UserEntity.Address.City -> UserDTO.AddressCity。
public class UserEntity { public int Id { get; set; } public string Name { get; set; }public Address Address { get; set; } }public class Address { public string City { get; set; } public string Country { get; set; } }public class UserDTO { public int Id { get; set; } public string Name { get; set; } public string AddressCity { get; set; } public string AddressCountry { get; set; } }

集合映射AutoMapper除了可以映射单个对象外,也可以映射集合对象。
CreateMap< UserEntity, UserDTO> (); var userList = new List< UserEntity> { new UserEntity { Id = 1, Name="Test1" }, new UserEntity { Id = 2, Name="Test2" }, }; var dtoList = mapper.Map< List< UserDTO> > (userList);

public class UserEntity { public int Id { get; set; } public string Name { get; set; }public List< AddressEntity> AddressList { get; set; } }public class AddressEntity { public string City { get; set; } public string Country { get; set; } }public class UserDTO { public int Id { get; set; } public string Name { get; set; }public List< AddressDTO> AddressList { get; set; } }public class AddressDTO { public string City { get; set; } public string Country { get; set; } }CreateMap< AddressEntity, AddressDTO> (); CreateMap< UserEntity, UserDTO> (); var user = new UserEntity { Id = 1, Name = "Test", AddressList = new List< AddressEntity> { new AddressEntity { City = "ShangHai", Country = "China"}, new AddressEntity { City = "BeiJing", Country = "China"} } }; var userDTO = mapper.Map< UserDTO> (user);

投影当把一个源值投影到一个不精准匹配源结构的目标值时,使用MapFrom指明成员映射定义。
public class UserEntity { public int Id { get; set; } public string Name { get; set; } public DateTime BirthDate { get; set; } }public class UserDTO { public int Id { get; set; } public string Name { get; set; } public string BirthYear { get; set; } public string BirthMonth { get; set; } }public class UserProfile : Profile { public UserProfile() { CreateMap< UserEntity, UserDTO> () .ForMember(d => d.BirthYear, o => o.MapFrom(s => s.BirthDate.Year)) .ForMember(d => d.BirthMonth, o => o.MapFrom(s => s.BirthDate.Month)); } }var user = new UserEntity { Id = 1, Name = "Test", BirthDate = DateTime.Today, }; var userDTO = mapper.Map< UserDTO> (user);

条件映射有些情况下,我们将只满足映射条件的才添加到属性上.
public class UserProfile : Profile { public UserProfile() { CreateMap< UserEntity, UserDTO> () .ForMember(d => d.Id, o => o.Condition(s => s.Id > 1)); } }

值转换AutoMapper可以配置值转换和空值替换
public class UserProfile : Profile { public UserProfile() { CreateMap< UserEntity, UserDTO> () .ForMember(d => d.Name, o => o.NullSubstitute("Default Name")) .ForMember(d => d.Name, o => o.AddTransform(val => string.Format("Name: {0}", val))); } }

设置转换前后行为有时候,在映射发生之前或之后,可能需要执行一些自定义的逻辑。
public class UserProfile : Profile { public UserProfile() { CreateMap< UserEntity, UserDTO> () .BeforeMap((s, d) => s.BirthDate = s.BirthDate.AddYears(-12)) .AfterMap((s, d) => d.BirthMonth = "July"); } }

配置验证及设置配置了映射,但是如何确定是否映射成功或者是否有字段没有映射呢?可以使用mapper.ConfigurationProvider.AssertConfigurationIsValid()来验证是否映射成功。但也可以指定单个字段不验证.
public class UserProfile : Profile { public UserProfile() { CreateMap< UserEntity, UserDTO> () .ForMember(d => d.NickName, o => o.Ignore()); } }

反向映射从6.1.0开始,AutoMapper通过ReverseMap可以实现反向映射。使用ReverseMap, 不用再创建DTO -> Entity的映射, 而且还能保留正向的映射规则。
public class UserProfile : Profile { public UserProfile() { CreateMap< UserEntity, UserDTO> () .ReverseMap(); } }

自定义转换器有些情况下目标字段类型和源字段类型不一致,可以通过类型转换器实现映射,类型转换器有三种实现方式:
void ConvertUsing(Func< TSource, TDestination> mappingFunction); void ConvertUsing(ITypeConverter< TSource, TDestination> converter); void ConvertUsing< TTypeConverter> () where TTypeConverter : ITypeConverter< TSource, TDestination> ;

自定义解析器某些情况下,解析规则会很复杂,使用自带的解析规则无法实现。这时可以自定义解析规则,可以通过以下三种方式使用自定义的解析器:
ResolveUsing< TValueResolver> ResolveUsing(typeof(CustomValueResolver)) ResolveUsing(aValueResolverInstance)

public class UserEntity { public string FirstName { get; set; } public string LastName { get; set; } }public class UserDTO { public string Name { get; set; } }public class UserNameResolver : IValueResolver< UserEntity, UserDTO, string> { public string Resolve(UserEntity source, UserDTO destination, string destMember, ResolutionContext context) { if (source != null & & !string.IsNullOrEmpty(source.FirstName) & & !string.IsNullOrEmpty(source.LastName)) { return string.Format("{0} {1}", source.FirstName, source.LastName); }return string.Empty; } }public class UserProfile : Profile { public UserProfile() { CreateMap< UserEntity, UserDTO> () .ForMember(d => d.Name, o => o.ResolveUsing< UserNameResolver> ()); } }

参考
  • automapper
  • AutoMapper 使用总结
  • http://www.cnblogs.com/farb/p/4932692.html

    推荐阅读