編輯于 2020/03/12
一. Dto是什么 '?'
DTO是Data Transfer Object 的簡(jiǎn)寫,既數(shù)據(jù)傳輸對(duì)象。
那viewModel和DTO又是什么關(guān)系呢?
viewModel更偏向于展示的數(shù)據(jù),而DTO是數(shù)據(jù)的傳輸,用于在服務(wù)器與客戶端之間或服務(wù)器與服務(wù)器之間進(jìn)行數(shù)據(jù)傳遞,實(shí)際上是不一樣的。
二. Dto的作用
DTO本身不是業(yè)務(wù)對(duì)象,他是根據(jù)UI需求進(jìn)行設(shè)計(jì)的。簡(jiǎn)單來說Model面向業(yè)務(wù),我們是通過后端業(yè)務(wù)來定義Model的。而DTO是面向UI,通過UI的需求來定義的,通過DTO我們實(shí)現(xiàn)了表現(xiàn)層與Model層之間的解耦,表現(xiàn)層不引用Model。如果開發(fā)過程中我們的模型變了,而界面沒變,我們只需改Model而不需要去改動(dòng)表現(xiàn)層。
三. 博主的理解
1.舉個(gè)例子,假設(shè)我本身就是個(gè)“對(duì)象模型”,我是個(gè)博主,.net程序員。這些信息是可以暴露出來的,就是dto傳輸?shù)膬?nèi)容,但是“我”這個(gè)對(duì)象模型不僅僅包含了這些信息,還有地址,電話。這些信息是我不想暴露出來的
2.再舉個(gè)例子,一個(gè)人的字段信息性別表示在數(shù)據(jù)庫為 null,0,1
在windows客戶端可能需要顯示“男人”
在ios端可能需要顯示“man”
在android端可能需要顯示“male”
有些字段我可能不想,也不需要發(fā)送給前端接收,有些字段我可能需要加工一下
這就可以通過Dto來實(shí)現(xiàn)
四. 實(shí)現(xiàn)的方式
環(huán)境
visual studio 2019
Core 3.1 WebApi
Models文件
實(shí)體類
public class GoodsEntity
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public DateTime? CreateTime { get; set; }
public bool IsDeleted { get; set; }
}
Dto類
public class GoodsDto
{
public string GoodsName { get; set; }
public decimal Price { get; set; }
public string CreateTime { get; set; }
public string Content { get; set; }
public bool IsDeleted { get; set; }
}
可以發(fā)現(xiàn)Dto中3個(gè)變化
createTime字段變成了String
沒有Id字段
多了Content字段
1. 通過類與類屬性賦值來實(shí)現(xiàn)

這種方式簡(jiǎn)單,但是當(dāng)是一個(gè)List時(shí),或者屬性很多時(shí),就會(huì)比較麻煩。
2. 通過AutoMapper實(shí)現(xiàn)
-
安裝AutoMapper
使用nuget搜索AutoMapper安裝
AutoMapper包 -
在Startup中添加AutoMapper
public void ConfigureServices(IServiceCollection services) { services.AddControllers(); #region Automapper services.AddAutoMapper(typeof(Startup)); #endregion } -
創(chuàng)建AutoMapper映射規(guī)則,得告訴AutoMapper映射關(guān)系
文件目錄AutoMapperConfigs.cs
public class AutoMapperConfigs { public static MapperConfiguration RegisterMappings() { return new MapperConfiguration(cfg => { cfg.AddProfile(new GoodsProfile()); }); } }GoodsProfile.cs
// 添加你的實(shí)體映射關(guān)系. public class GoodsProfile : Profile { public GoodsProfile() { // GoodsEntity轉(zhuǎn)GoodsDto. CreateMap<GoodsEntity, GoodsDto>() // 映射發(fā)生之前 // 映射之前統(tǒng)一處理 .BeforeMap((ent, dto) => ent.Price = ent.Price + 10) // 默認(rèn)賦值 .BeforeMap((src, dest) => src.CreateTime = src.CreateTime == null ? (new DateTime(2012, 12, 12)) : src.CreateTime) // 映射匹配 把GoodsEntity.Name匹配到GoodsDto.Name .ForMember(dto => dto.GoodsName, opt => opt.MapFrom(ent => ent.Name)) .ForMember(dto => dto.CreateTime, opt => opt.MapFrom(ent => ((DateTime)ent.CreateTime).ToString("yyyy-MM-dd"))) // 匹配的過程中賦值 .ForMember(dto => dto.Price, opt => opt.MapFrom(ent => ent.Price + 10)) // 映射發(fā)生之后 .AfterMap((ent, dto) => dto.GoodsName = dto.Price < 40 ? "N/A." : dto.GoodsName) .AfterMap((src, dest) => dest.Content = "完成映射后"); // 最簡(jiǎn)單的匹配,屬性字段/類型等完全一致 // GoodsDto轉(zhuǎn)GoodsEntity. CreateMap<GoodsDto, GoodsEntity>(); } } -
在DtoController中修改添加代碼
[HttpGet] [Route(nameof(GetGoods))] public ActionResult GetGoods() { ////實(shí)例化實(shí)體 GoodsEntity goodsEntity = new GoodsEntity() { Id = 1, Name = "商品1", Price = 23.25M, CreateTime = DateTime.Now, IsDeleted = true, }; var goodsDtos = _mapper.Map<GoodsDto>(goodsEntity); return Ok(goodsDtos); } -
運(yùn)行后結(jié)果如下
運(yùn)行結(jié)果
源碼鏈接
下載dtoAutoMapper分支即可


