参考 :
- http://www.cnblogs.com/xishuai/p/3700052.html
- http://www.cnblogs.com/xishuai/p/3704435.html
- http://www.cnblogs.com/xishuai/p/3708483.html
automapper 并不是 dotnet core 的东西啦, 只是记入在这里而已.
automapper 是一个简单的库, 帮我们处理对象和对象的映射.
我们做开发通常会用到 ef core,
entity 基本上对应 sql 的一个 table, 但是通常数据库的结构会比较复杂, 要范式, 不要冗余嘛.
但是呢, 我们在做 view , 或者在 post, put resource 的时候往往不需要那么多和那么复杂的结构.
所以就有了 DTO , data transfer object 的概念.
而 entity <-> DTO 就是一个很繁琐的映射. 于是就有了 automapper 这个比较智能的工具库.
nuget 安装 : AutoMapper.Extensions.Microsoft.DependencyInjection
在 service config 添加 services.AddAutoMapper();
定义一个 Profile (我的做法是把所有的映射都写在一起, 一堆就是了, 感觉比较容易找, 遇到要添加 column 的情况下, 就有很多 dto 要跟着添加嘛)
- public class UserProfile : Profile
- {
- public UserProfile()
- {
- CreateMap<Member, MemberDto>();
- }
- }
1. 复杂类型到简单类型
- public class Member {
- public Address address { get; set; }
- }
- public class Address {
- public string country { get; set; }
- }
- public class MemberDto {
- public string addressCountry { get; set; }
- }
两层变一层
- public class HomeController : Controller
- {
- private readonly IMapper Mapper;
- public HomeController(
- IMapper mapper
- ) {
- Mapper = mapper;
- }
- public IActionResult Index()
- {
- var member = new Member { address = new Address { country = "Malaysia" } };
- var memberDto = Mapper.Map<MemberDto>(member);
- var result = memberDto.addressCountry; // Malaysia
- return View();
- }
- }
这样就可以了.
2. 简单类型到复杂类型
用反转就可以了
- CreateMap<Member, MemberDto>().ReverseMap();
- // ReverseMap 是好东西, 但有些东西不能直接反转, 比如 ignore
- CreateMap<Member, MemberDto>().ForMember(dest => dest.name, opt => opt.Ignore()).ReverseMap().ForPath(dest => dest.name, opt => opt.Ignore());
如果不写 ForPath 只有 to dto 的时候回 ignore.
3. 自定义映射
CreateMap<Member, MemberDto>().ForMember(dest => dest.addressCountry, opt => opt.MapFrom(sour => sour.address.country));
使用 ForMember + MapFrom 可以完全自己定义.
dest = destination 目的地, sour = source, automapper 就是 source -> destination 的概念.
4. ignore 无视
- CreateMap<Member, MemberDto>().ForMember(dest => dest.name, opt => opt.Ignore()).ReverseMap().ForPath(dest => dest.name, opt => opt.Ignore());
- 5.collection
不需要任何新配置
var members = Mapper.Map<List<Member>>(membersDto);
6. 继承
继承是当我们有这样的需求的时候
假设 Person -> Man -> Boy
- var x = new Boy {
- propBoy = "da", propMan = "d", name = "a"
- };
- var g = Mapper.Map<PersonDto>(x);
我们希望 g 是一个 BoyDto
- CreateMap<Person, PersonDto>().Include<Man, ManDto>().Include<Boy, BoyDto>();
- CreateMap<Man, ManDto>();
- CreateMap<Boy, BoyDto>();
需要如上的配置才行哦, 缺一不可.
到这里我们可以看出来, automapper 的 config 主要就是针对, 当某个类型需要被映射到另一个类型时, 它需要怎样的配置.
7. 原始类型转换
既然是类型转换, 那 string 可以 to int 映射吗 ?
- Mapper.CreateMap<string, int>().ConvertUsing(Convert.ToInt32);
- Mapper.CreateMap<string, int>().ConvertUsing(stringValue => Convert.ToInt32(stringValue)); // 表达式也可以
完全没有问题.
refer : http://docs.automapper.org/en/latest/Custom-type-converters.html?highlight=custom
8. 值得映射
上面说到有时候我们需要些自定义的映射, 那是因为它原始没有嘛. 但是如果一直写重复也不行.
所以还是可以封装的.
- public class UserProfile : Profile
- {
- public UserProfile()
- {
- CreateMap<Source, Destination>()
- .ForMember(dest => dest.Total, opt => opt.MapFrom<CustomResolver>()));
- }
- }
- public class Source
- {
- public int Value1 { get; set; }
- public int Value2 { get; set; }
- }
- public class Destination
- {
- public int Total { get; set; }
- }
- public class CustomResolver : IValueResolver<Source, Destination, int>
- {
- public int Resolve(Source source, Destination destination, int member, ResolutionContext context)
- {
- return source.Value1 + source.Value2;
- }
- }
真实场景下, 把 Source 和 Destination 换成接口.
- refer : http://docs.automapper.org/en/latest/Custom-value-resolvers.html
- 9. default value
- Mapper.CreateMap<Source, Destination>().ForMember(dest => dest.Value, opt => opt.NullSubstitute("Other Value"));
如果映射时 source 没有值, 我们可以通过这里给一个 default 给 destination.
总结 :
automapper 就是帮助我们写映射的. 我们使用的时候一定要记得这一点, 不要让它去做超出范围的事情.
来源: http://www.bubuko.com/infodetail-2866503.html