# DTO数据传输对象
简单来说Model面向业务,我们是通过业务来定义Model的。而DTO是面向界面UI,是通过UI的需求来定义的。通过DTO我们实现了表现层与Model之间的解耦,表现层不引用Model,如果开发过程中我们的模型改变了,而界面没变,我们就只需要改Model而不需要去改表现层中的东西。
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; }
}
# 最简单的用法
AutoMapper会根据字段名称去自动对于,忽略大小写。
Mapper.Initialize(x => x.CreateMap<User, UserDto>());
User user = new User()
{
Id = 1,
Name = "caoyc",
Age = 20
};
var dto = Mapper.Map<UserDto>(user);
# 如果属性名称不同
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
空值替换允许我们将源对象中的空值在转换为目标对象的值的时候,使用指定的值来替换空值。
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("值为空"));
}
}
# 忽略属性Ignore
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
};
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
当满足条件时才进行映射字段,例如人类年龄,假设我们现在人类年龄范围为100岁,只有满足在这个条件才进行映射。
public class User
{
public int Age { get; set; }
}
public class UserDto
{
public int Age { get; set; }
}
public class UserProfile : Profile
{
protected override void Configure()
{
CreateMap<User, UserDto>()
.ForMember(dest=>dest.Age,opt=>opt.Condition(src=>src.Age<=100));
}
}
使用代码
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);
# AutoMapperHelper
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>();
# NET CORE 使用AutoMapper
# 安装依赖包
- AutoMapper
- AutoMapper.Extensions.Microsoft.Dependencyinjection
# 注册服务
services.AddAutoMapper(typeof(AutoMapperConfiguration));
# 创建映射规则
public class AutoMapperConfiguration:Profile{
public AutoMapperConfiguration(){
CreateMap<GoodsEntity,GoodsDto>()
//映射发生之前统一处理 操作 src
.BeforeMap((src,dest)=>src.Price=src.Price+10)
.BeforeMap((src,dest)=>src.CreatTime=src.CreatTime==null?DateTime.Now:src.CreatTime)
//映射匹配
.ForMember(dest=>dest.GoodsName,opt=>opt.MapFrom(src=>src.Name))
.ForMember(dest=>dest.CreatTime,opt=>opt.MapFrom(src=>src.CreatTime.ToString("yyyy-MM-dd")))
//匹配过程中赋值
.ForMember(dest=>dest.Price,opt=>opt.MapFrom(src=>src.Price+10))
//忽略某个属性的映射
.ForMemeber(dest>dest.IsDeleted,opt=>opt.Ignore())
//合并
.ForMemeber(dest>dest.GoodsName,opt=>opt.MapFrom(src=>src.Name+src.Brands.Name))
//映射发生之后 操作 dest
.AfterMap((src,dest)=>src.GoodsName=dest.Price<40?"":dest.GoodsName));
//最简单的匹配,属性字段、类型完全一致
//实体转DTO
CreateMap<GoodsEntity,GoodsDto>();
}
}
# 使用
public class TestController:ControllerBase{
private readonly IMapper _mapper;
public TestController(IMapper mapper){
_mapper=mapper;
}
public async Task<List<string>> GetList(){
var goodsDtos=_mapper.Map<List<GoodsDto>>(allGoodsList);
return new List<string>{goodsDtos};
}
}
← EntityFramework Cache →