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