ASP.NET Core使用AutoMapper實(shí)現(xiàn)實(shí)體映射
一、前言
在實(shí)際的項(xiàng)目開(kāi)發(fā)過(guò)程中,我們使用各種ORM框架可以使我們快捷的獲取到數(shù)據(jù),并且可以將獲取到的數(shù)據(jù)綁定到對(duì)應(yīng)的List<T>中,然后頁(yè)面或者接口直接顯示List<T>中的數(shù)據(jù)。但是我們最終想要顯示在視圖或者接口中的數(shù)據(jù)和數(shù)據(jù)庫(kù)實(shí)體之間可能存在著差異,一般的做法就是去創(chuàng)建一些對(duì)應(yīng)的“模型”類,然后對(duì)獲取到的數(shù)據(jù)再次進(jìn)行處理,從而滿足需求。
因此,如果便捷的實(shí)現(xiàn)數(shù)據(jù)庫(kù)持久化對(duì)象與模型對(duì)象之間的實(shí)體映射,避免在去代碼中手工實(shí)現(xiàn)這一過(guò)程,就可以大大降低開(kāi)發(fā)的工作量。AutoMapper就是可以幫助我們實(shí)現(xiàn)實(shí)體轉(zhuǎn)換過(guò)程的工具。
二、使用AutoMapper實(shí)現(xiàn)實(shí)體映射
AutoMapper是一個(gè)OOM(Object-Object-Mapping)組件,從它的英文名字中可以看出,AutoMapper主要是為了實(shí)現(xiàn)實(shí)體間的相互轉(zhuǎn)換,從而避免我們每次采用手工的方式進(jìn)行轉(zhuǎn)換。在沒(méi)有OOM這類組件之前,如果我們需要實(shí)現(xiàn)實(shí)體之間的轉(zhuǎn)換,只能使用手工修改代碼,然后逐個(gè)賦值的方式實(shí)現(xiàn)映射,而有了OOM組件,可以很方便的幫助我們實(shí)現(xiàn)這一需求??聪旅娴囊粋€(gè)例子。
首先創(chuàng)建一個(gè)ASP.NET Core WebApi項(xiàng)目:
添加一個(gè)Student實(shí)體類:
namespace AutoMapperDemo.Model { public class Student { public int ID { get; set; } public string Name { get; set; } public int Age { get; set; } public string Gender { get; set; } } }
添加StudentDTO類,跟Student屬性一致。
然后添加一個(gè)類,模擬一些測(cè)試數(shù)據(jù):
using AutoMapperDemo.Model; using System.Collections.Generic; namespace AutoMapperDemo { public class Data { public static List<Student> ListStudent { get; set; } public static List<Student> GetList() { ListStudent = new List<Student>(); for (int i = 0; i < 3; i++) { Student student = new Student() { ID=i, Name=$"測(cè)試_{i}", Age=20, Gender="男" }; ListStudent.Add(student); } return ListStudent; } } }
添加Student控制器,通過(guò)Get方法獲取所有的值:
using System.Collections.Generic; using System.Threading.Tasks; using AutoMapperDemo.Model; using Microsoft.AspNetCore.Mvc; namespace AutoMapperDemo.Controllers { [Route("api/[controller]")] [ApiController] public class StudentController : ControllerBase { [HttpGet] public async Task<List<Student>> Get() { List<Student> list = new List<Student>(); list = await Task.Run<List<Student>>(() => { return Data.GetList(); }); return list; } } }
使用Postman進(jìn)行測(cè)試:
這樣返回的數(shù)據(jù)直接就是數(shù)據(jù)庫(kù)對(duì)應(yīng)的實(shí)體類類型。這時(shí)需求改變了,我們要返回StudentDTO類型的數(shù)據(jù),這時(shí)就需要修改代碼:
using System.Collections.Generic; using System.Threading.Tasks; using AutoMapperDemo.DTO; using AutoMapperDemo.Model; using Microsoft.AspNetCore.Mvc; namespace AutoMapperDemo.Controllers { [Route("api/[controller]")] [ApiController] public class StudentController : ControllerBase { [HttpGet] public async Task<List<Student>> Get() { List<Student> list = new List<Student>(); list = await Task.Run<List<Student>>(() => { return Data.GetList(); }); return list; } [HttpGet("GetDTO")] public async Task<List<StudentDTO>> GetDto() { List<StudentDTO> list = new List<StudentDTO>(); List<Student> listStudent = await Task.Run<List<Student>>(() => { return Data.GetList(); }); // 循環(huán)給屬性賦值 foreach (var item in listStudent) { StudentDTO dto = new StudentDTO(); dto.ID = item.ID; dto.Name = item.Name; dto.Age = item.Age; dto.Gender = item.Gender; // 加入到集合中 list.Add(dto); } return list; } } }
還是使用Postman進(jìn)行測(cè)試:
可以看到:這時(shí)返回的是DTO類型的數(shù)據(jù)。這種情況就是我們上面說(shuō)的,需要手動(dòng)修改代碼,然后循環(huán)給對(duì)應(yīng)的屬性進(jìn)行賦值。這里Student類只有4個(gè)屬性,如果屬性非常多,或者很多地方使用到了,如果還是采用這種方式進(jìn)行賦值,那么就會(huì)很麻煩。假如以后其中的一個(gè)屬性名稱改變了,那么所有的地方也都需要修改,工作量就會(huì)很大。這時(shí)就需要使用AutoMapper解決。
首先引入AutoMapper包,直接在NuGet中引入:
這里選擇安裝AutoMapper.Extensions.Microsoft.DependencyInjection這個(gè)包。這個(gè)包主要是為了讓我們可以通過(guò)依賴注入的方式去使用AutoMapper。
新建StudentProfile類,繼承自AutoMapper的Profile類,在無(wú)參構(gòu)造函數(shù)中,我們就可以通過(guò) CreateMap 方法去創(chuàng)建兩個(gè)實(shí)體間的映射關(guān)系。
using AutoMapper; using AutoMapperDemo.DTO; using AutoMapperDemo.Model; namespace AutoMapperDemo.AutoMapper { /// <summary> /// 繼承自Profile類 /// </summary> public class StudentProfile: Profile { /// <summary> /// 構(gòu)造函數(shù)中實(shí)現(xiàn)映射 /// </summary> public StudentProfile() { // Mapping // 第一次參數(shù)是源類型(這里是Model類型),第二個(gè)參數(shù)是目標(biāo)類型(這里是DTO類型) CreateMap<Student, StudentDTO>(); } } }
這里的 Profile有什么用呢?services.AddAutoMapper他會(huì)自動(dòng)找到所有繼承了Profile的類然后進(jìn)行配置。
然后修改Student控制器,通過(guò)構(gòu)造函數(shù)使用AutoMapper的注入,并使用AutoMapper實(shí)現(xiàn)自動(dòng)映射:
using System.Collections.Generic; using System.Threading.Tasks; using AutoMapper; using AutoMapperDemo.DTO; using AutoMapperDemo.Model; using Microsoft.AspNetCore.Mvc; namespace AutoMapperDemo.Controllers { [Route("api/[controller]")] [ApiController] public class StudentController : ControllerBase { private readonly IMapper _mapper; /// <summary> /// 通過(guò)構(gòu)造函數(shù)實(shí)現(xiàn)依賴注入 /// </summary> /// <param name="mapper"></param> public StudentController(IMapper mapper) { _mapper = mapper; } [HttpGet] public async Task<List<Student>> Get() { List<Student> list = new List<Student>(); list = await Task.Run<List<Student>>(() => { return Data.GetList(); }); return list; } [HttpGet("GetDTO")] public async Task<List<StudentDTO>> GetDto() { List<StudentDTO> list = new List<StudentDTO>(); List<Student> listStudent = await Task.Run<List<Student>>(() => { return Data.GetList(); }); //// 循環(huán)給屬性賦值 //foreach (var item in listStudent) //{ // StudentDTO dto = new StudentDTO(); // dto.ID = item.ID; // dto.Name = item.Name; // dto.Age = item.Age; // dto.Gender = item.Gender; // // 加入到集合中 // list.Add(dto); //} // 使用AutoMapper進(jìn)行映射 list = _mapper.Map<List<StudentDTO>>(listStudent); return list; } } }
修改Startup類的ConfigureServices方法,添加AutoMapper:
public void ConfigureServices(IServiceCollection services) { #region 使用AutoMapper // 參數(shù)類型是Assembly類型的數(shù)組 表示AutoMapper將在這些程序集數(shù)組里面遍歷尋找所有繼承了Profile類的配置文件 // 在當(dāng)前作用域的所有程序集里面掃描AutoMapper的配置文件 services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies()); #endregion services.AddControllers(); }
再次使用Postman進(jìn)行測(cè)試:
可以看到,這樣也實(shí)現(xiàn)了我們的需求,而且還不需要進(jìn)行手動(dòng)映射。
上面的示例中,Student和StudentDTO類里面的屬性名稱都是一樣的,如果屬性名稱不一樣呢?我們把StudentDTO類里面的ID改為StudentID,然后修改映射代碼:
using AutoMapper; using AutoMapperDemo.DTO; using AutoMapperDemo.Model; namespace AutoMapperDemo.AutoMapper { /// <summary> /// 繼承自Profile類 /// </summary> public class StudentProfile: Profile { /// <summary> /// 構(gòu)造函數(shù)中實(shí)現(xiàn)映射 /// </summary> public StudentProfile() { // Mapping // 第一次參數(shù)是源類型(這里是Model類型),第二個(gè)參數(shù)是目標(biāo)類型(這里是DTO類型) // CreateMap<Student, StudentDTO>(); // 使用自定義映射 Student類的ID映射到StudentDTO類的StudentID CreateMap<Student, StudentDTO>() .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); }); } } }
再次使用Postman進(jìn)行測(cè)試:
這樣就實(shí)現(xiàn)了自定義映射。這里是映射了一個(gè)字段,如果是多個(gè)字段不同呢? 修改StudentDTO類:
namespace AutoMapperDemo.DTO { public class StudentDTO { public int StudentID { get; set; } public string StudentName { get; set; } public int StudentAge { get; set; } public string StudentGender { get; set; } } }
然后修改映射配置類:
using AutoMapper; using AutoMapperDemo.DTO; using AutoMapperDemo.Model; namespace AutoMapperDemo.AutoMapper { /// <summary> /// 繼承自Profile類 /// </summary> public class StudentProfile: Profile { /// <summary> /// 構(gòu)造函數(shù)中實(shí)現(xiàn)映射 /// </summary> public StudentProfile() { // Mapping // 第一次參數(shù)是源類型(這里是Model類型),第二個(gè)參數(shù)是目標(biāo)類型(這里是DTO類型) // CreateMap<Student, StudentDTO>(); // 使用自定義映射 Student類的ID映射到StudentDTO類的StudentID //CreateMap<Student, StudentDTO>() // .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); }); // 對(duì)多個(gè)屬性進(jìn)行自定義映射 CreateMap<Student, StudentDTO>() .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); }) .ForMember(destinationMember: des => des.StudentName, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Name); }) .ForMember(destinationMember: des => des.StudentAge, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Age); }) .ForMember(destinationMember: des => des.StudentGender, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Gender); }); } } }
在使用Postman進(jìn)行測(cè)試:
這樣就實(shí)現(xiàn)了多個(gè)屬性的自定義映射。
上面的實(shí)例中是從Student映射到StudentDTO,那么可以從StudentDTO映射到Student嗎?答案是肯定的,只需要在映射的最后使用ReverseMap()方法即可:
using AutoMapper; using AutoMapperDemo.DTO; using AutoMapperDemo.Model; namespace AutoMapperDemo.AutoMapper { /// <summary> /// 繼承自Profile類 /// </summary> public class StudentProfile: Profile { /// <summary> /// 構(gòu)造函數(shù)中實(shí)現(xiàn)映射 /// </summary> public StudentProfile() { // Mapping // 第一次參數(shù)是源類型(這里是Model類型),第二個(gè)參數(shù)是目標(biāo)類型(這里是DTO類型) // CreateMap<Student, StudentDTO>(); // 使用自定義映射 Student類的ID映射到StudentDTO類的StudentID //CreateMap<Student, StudentDTO>() // .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); }); // 對(duì)多個(gè)屬性進(jìn)行自定義映射 CreateMap<Student, StudentDTO>() .ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); }) .ForMember(destinationMember: des => des.StudentName, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Name); }) .ForMember(destinationMember: des => des.StudentAge, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Age); }) .ForMember(destinationMember: des => des.StudentGender, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.Gender); }) // ReverseMap表示雙向映射 .ReverseMap(); } } }
我們修改Data,里面增加一個(gè)Add方法,可以將Student添加到集合中:
using AutoMapperDemo.Model; using System.Collections.Generic; namespace AutoMapperDemo { public class Data { public static List<Student> ListStudent { get; set; } static Data() { ListStudent = new List<Student>(); for (int i = 0; i < 3; i++) { Student student = new Student() { ID = i, Name = $"測(cè)試_{i}", Age = 20, Gender = "男" }; ListStudent.Add(student); } } public static List<Student> GetList() { return ListStudent; } public static void Add(Student entity) { ListStudent.Add(entity); } } }
修改Student控制器,添加一個(gè)Post方法,傳入的參數(shù)的StudentDTO類型:
using System.Collections.Generic; using System.Threading.Tasks; using AutoMapper; using AutoMapperDemo.DTO; using AutoMapperDemo.Model; using Microsoft.AspNetCore.Mvc; namespace AutoMapperDemo.Controllers { [Route("api/[controller]")] [ApiController] public class StudentController : ControllerBase { private readonly IMapper _mapper; /// <summary> /// 通過(guò)構(gòu)造函數(shù)實(shí)現(xiàn)依賴注入 /// </summary> /// <param name="mapper"></param> public StudentController(IMapper mapper) { _mapper = mapper; } [HttpGet] public async Task<List<Student>> Get() { List<Student> list = new List<Student>(); list = await Task.Run<List<Student>>(() => { return Data.GetList(); }); return list; } [HttpGet("GetDTO")] public async Task<List<StudentDTO>> GetDto() { List<StudentDTO> list = new List<StudentDTO>(); List<Student> listStudent = await Task.Run<List<Student>>(() => { return Data.GetList(); }); //// 循環(huán)給屬性賦值 //foreach (var item in listStudent) //{ // StudentDTO dto = new StudentDTO(); // dto.ID = item.ID; // dto.Name = item.Name; // dto.Age = item.Age; // dto.Gender = item.Gender; // // 加入到集合中 // list.Add(dto); //} // 使用AutoMapper進(jìn)行映射 list = _mapper.Map<List<StudentDTO>>(listStudent); return list; } [HttpPost] public async Task<List<Student>> Post([FromBody]StudentDTO entity) { List<Student> list = new List<Student>(); // 將StudentDTO反向映射為Student類型 Student student = _mapper.Map<Student>(entity); // 添加到集合中 Data.Add(student); // 返回增加后的數(shù)組,這里返回Student list = await Task.Run<List<Student>>(() => { return Data.GetList(); }); return list; } } }
使用Postman進(jìn)行測(cè)試:
返回結(jié)果:
這樣就實(shí)現(xiàn)了映射的反轉(zhuǎn)。
具體其它API功能,參考AutoMapper官網(wǎng):https://automapper.readthedocs.io/en/latest/index.html
到此這篇關(guān)于ASP.NET Core使用AutoMapper實(shí)現(xiàn)實(shí)體映射的文章就介紹到這了。希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Asp.net(C#)實(shí)現(xiàn)驗(yàn)證碼功能代碼
asp.net驗(yàn)證碼的實(shí)現(xiàn)方法2008-10-10.NET下通過(guò)HttpListener實(shí)現(xiàn)簡(jiǎn)單的Http服務(wù)
這篇文章主要為大家詳細(xì)介紹了.NET下通過(guò)HttpListener實(shí)現(xiàn)簡(jiǎn)單Http服務(wù)的相關(guān)資料,感興趣的小伙伴們可以參考一下2016-09-09asp.net DataList與Repeater用法區(qū)別
Repeater比DataList要好一些,如果不是很大數(shù)據(jù)量的話,這點(diǎn)差別是體現(xiàn)不來(lái)的。2009-12-12asp.net中倒計(jì)時(shí)自動(dòng)跳轉(zhuǎn)頁(yè)面的實(shí)現(xiàn)方法(使用javascript)
本篇文章介紹了,asp.net中倒計(jì)時(shí)自動(dòng)跳轉(zhuǎn)頁(yè)面的實(shí)現(xiàn)方法(使用javascript)。需要的朋友參考下2013-05-05在ASP.NET Core中應(yīng)用HttpClient獲取數(shù)據(jù)和內(nèi)容
這篇文章主要介紹了在ASP.NET Core中集成和使用HttpClient獲取數(shù)據(jù)和內(nèi)容,幫助大家更好的理解和學(xué)習(xí)使用ASP.NET Core,感興趣的朋友可以了解下2021-03-03Windows下Visual Studio 2017安裝配置方法圖文教程
這篇文章主要為大家詳細(xì)介紹了Windows下Visual Studio 2017安裝配置方法圖文教程,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-06-06如何使用Rotativa在ASP.NET Core MVC中創(chuàng)建PDF詳解
這篇文章主要給大家介紹了關(guān)于如何使用Rotativa在ASP.NET Core MVC中創(chuàng)建PDF的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-02-02ADO.NET通用數(shù)據(jù)庫(kù)訪問(wèn)類
這篇文章主要為大家介紹了ADO.NET通用數(shù)據(jù)庫(kù)訪問(wèn)類,利用ADO.NET的體系架構(gòu)打造通用的數(shù)據(jù)庫(kù)訪問(wèn)通用類,感興趣的小伙伴們可以參考一下2016-03-03asp.net開(kāi)發(fā)微信公眾平臺(tái)之驗(yàn)證消息的真實(shí)性
這篇文章主要介紹了asp.net開(kāi)發(fā)微信公眾平臺(tái)之驗(yàn)證消息的真實(shí)性的相關(guān)資料,需要的朋友可以參考下2015-06-06ASP.NET 2.0 中的創(chuàng)建母版頁(yè)
ASP.NET 2.0 中的創(chuàng)建母版頁(yè)...2006-09-09