ASP.NET Core教程:ASP.NET Core使用AutoMapper

2024-01-21 11:48

本文主要是介绍ASP.NET Core教程:ASP.NET Core使用AutoMapper,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、前言

在实际的项目开发过程中,我们使用各种ORM框架可以使我们快捷的获取到数据,并且可以将获取到的数据绑定到对应的List<T>中,然后页面或者接口直接显示List<T>中的数据。但是我们最终想要显示在视图或者接口中的数据和数据库实体之间可能存在着差异,一般的做法就是去创建一些对应的“模型”类,然后对获取到的数据再次进行处理,从而满足需求。

因此,如果便捷的实现数据库持久化对象与模型对象之间的实体映射,避免在去代码中手工实现这一过程,就可以大大降低开发的工作量。AutoMapper就是可以帮助我们实现实体转换过程的工具。

二、使用AutoMapper实现实体映射

AutoMapper是一个OOM(Object-Object-Mapping)组件,从它的英文名字中可以看出,AutoMapper主要是为了实现实体间的相互转换,从而避免我们每次采用手工的方式进行转换。在没有OOM这类组件之前,如果我们需要实现实体之间的转换,只能使用手工修改代码,然后逐个赋值的方式实现映射,而有了OOM组件,可以很方便的帮助我们实现这一需求。看下面的一个例子。

首先创建一个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属性一致。

然后添加一个类,模拟一些测试数据:

复制代码

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进行测试:

这样返回的数据直接就是数据库对应的实体类类型。这时需求改变了,我们要返回StudentDTO类型的数据,这时就需要修改代码:

复制代码

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();});// 循环给属性赋值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类型的数据。这种情况就是我们上面说的,需要手动修改代码,然后循环给对应的属性进行赋值。这里Student类只有4个属性,如果属性非常多,或者很多地方使用到了,如果还是采用这种方式进行赋值,那么就会很麻烦。假如以后其中的一个属性名称改变了,那么所有的地方也都需要修改,工作量就会很大。这时就需要使用AutoMapper解决。

首先引入AutoMapper包,直接在NuGet中引入:

这里选择安装AutoMapper.Extensions.Microsoft.DependencyInjection这个包。这个包主要是为了让我们可以通过依赖注入的方式去使用AutoMapper。

新建StudentProfile类,继承自AutoMapper的Profile类,在无参构造函数中,我们就可以通过 CreateMap 方法去创建两个实体间的映射关系。

复制代码

using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;namespace AutoMapperDemo.AutoMapper
{/// <summary>/// 继承自Profile类/// </summary>public class StudentProfile: Profile{/// <summary>/// 构造函数中实现映射/// </summary>public StudentProfile(){// Mapping// 第一次参数是源类型(这里是Model类型),第二个参数是目标类型(这里是DTO类型)CreateMap<Student, StudentDTO>();}}
}

复制代码

这里的 Profile有什么用呢?services.AddAutoMapper他会自动找到所有继承了Profile的类然后进行配置。

然后修改Student控制器,通过构造函数使用AutoMapper的注入,并使用AutoMapper实现自动映射:

复制代码

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>/// 通过构造函数实现依赖注入/// </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();});循环给属性赋值//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// 参数类型是Assembly类型的数组 表示AutoMapper将在这些程序集数组里面遍历寻找所有继承了Profile类的配置文件// 在当前作用域的所有程序集里面扫描AutoMapper的配置文件services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());#endregionservices.AddControllers();
}

复制代码

再次使用Postman进行测试:

可以看到,这样也实现了我们的需求,而且还不需要进行手动映射。

上面的示例中,Student和StudentDTO类里面的属性名称都是一样的,如果属性名称不一样呢?我们把StudentDTO类里面的ID改为StudentID,然后修改映射代码:

复制代码

using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;namespace AutoMapperDemo.AutoMapper
{/// <summary>/// 继承自Profile类/// </summary>public class StudentProfile: Profile{/// <summary>/// 构造函数中实现映射/// </summary>public StudentProfile(){// Mapping// 第一次参数是源类型(这里是Model类型),第二个参数是目标类型(这里是DTO类型)// CreateMap<Student, StudentDTO>();// 使用自定义映射 Student类的ID映射到StudentDTO类的StudentIDCreateMap<Student, StudentDTO>().ForMember(destinationMember: des => des.StudentID, memberOptions: opt => { opt.MapFrom(mapExpression: map => map.ID); });}}
}

复制代码

再次使用Postman进行测试:

这样就实现了自定义映射。这里是映射了一个字段,如果是多个字段不同呢? 修改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>/// 构造函数中实现映射/// </summary>public StudentProfile(){// Mapping// 第一次参数是源类型(这里是Model类型),第二个参数是目标类型(这里是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进行测试:

这样就实现了多个属性的自定义映射。 

上面的实例中是从Student映射到StudentDTO,那么可以从StudentDTO映射到Student吗?答案是肯定的,只需要在映射的最后使用ReverseMap()方法即可:

复制代码

using AutoMapper;
using AutoMapperDemo.DTO;
using AutoMapperDemo.Model;namespace AutoMapperDemo.AutoMapper
{/// <summary>/// 继承自Profile类/// </summary>public class StudentProfile: Profile{/// <summary>/// 构造函数中实现映射/// </summary>public StudentProfile(){// Mapping// 第一次参数是源类型(这里是Model类型),第二个参数是目标类型(这里是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方法,传入的参数的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>/// 通过构造函数实现依赖注入/// </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();});循环给属性赋值//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);// 返回增加后的数组,这里返回Studentlist = await Task.Run<List<Student>>(() =>{return Data.GetList();});return list;}}
}

复制代码

使用Postman进行测试:

返回结果:

这样就实现了映射的反转。

具体其它API功能,参考AutoMapper官网:AutoMapper — AutoMapper documentation 

这篇关于ASP.NET Core教程:ASP.NET Core使用AutoMapper的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/629441

相关文章

使用animation.css库快速实现CSS3旋转动画效果

《使用animation.css库快速实现CSS3旋转动画效果》随着Web技术的不断发展,动画效果已经成为了网页设计中不可或缺的一部分,本文将深入探讨animation.css的工作原理,如何使用以及... 目录1. css3动画技术简介2. animation.css库介绍2.1 animation.cs

使用雪花算法产生id导致前端精度缺失问题解决方案

《使用雪花算法产生id导致前端精度缺失问题解决方案》雪花算法由Twitter提出,设计目的是生成唯一的、递增的ID,下面:本文主要介绍使用雪花算法产生id导致前端精度缺失问题的解决方案,文中通过代... 目录一、问题根源二、解决方案1. 全局配置Jackson序列化规则2. 实体类必须使用Long封装类3.

Python文件操作与IO流的使用方式

《Python文件操作与IO流的使用方式》:本文主要介绍Python文件操作与IO流的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、python文件操作基础1. 打开文件2. 关闭文件二、文件读写操作1.www.chinasem.cn 读取文件2. 写

PyQt6中QMainWindow组件的使用详解

《PyQt6中QMainWindow组件的使用详解》QMainWindow是PyQt6中用于构建桌面应用程序的基础组件,本文主要介绍了PyQt6中QMainWindow组件的使用,具有一定的参考价值,... 目录1. QMainWindow 组php件概述2. 使用 QMainWindow3. QMainW

使用Python自动化生成PPT并结合LLM生成内容的代码解析

《使用Python自动化生成PPT并结合LLM生成内容的代码解析》PowerPoint是常用的文档工具,但手动设计和排版耗时耗力,本文将展示如何通过Python自动化提取PPT样式并生成新PPT,同时... 目录核心代码解析1. 提取 PPT 样式到 jsON关键步骤:代码片段:2. 应用 JSON 样式到

java变量内存中存储的使用方式

《java变量内存中存储的使用方式》:本文主要介绍java变量内存中存储的使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、介绍2、变量的定义3、 变量的类型4、 变量的作用域5、 内存中的存储方式总结1、介绍在 Java 中,变量是用于存储程序中数据

关于Mybatis和JDBC的使用及区别

《关于Mybatis和JDBC的使用及区别》:本文主要介绍关于Mybatis和JDBC的使用及区别,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、JDBC1.1、流程1.2、优缺点2、MyBATis2.1、执行流程2.2、使用2.3、实现方式1、XML配置文件

macOS Sequoia 15.5 发布: 改进邮件和屏幕使用时间功能

《macOSSequoia15.5发布:改进邮件和屏幕使用时间功能》经过常规Beta测试后,新的macOSSequoia15.5现已公开发布,但重要的新功能将被保留到WWDC和... MACOS Sequoia 15.5 正式发布!本次更新为 Mac 用户带来了一系列功能强化、错误修复和安全性提升,进一步增

ubuntu20.0.4系统中安装Anaconda的超详细图文教程

《ubuntu20.0.4系统中安装Anaconda的超详细图文教程》:本文主要介绍了在Ubuntu系统中如何下载和安装Anaconda,提供了两种方法,详细内容请阅读本文,希望能对你有所帮助... 本文介绍了在Ubuntu系统中如何下载和安装Anaconda。提供了两种方法,包括通过网页手动下载和使用wg

Java资源管理和引用体系的使用详解

《Java资源管理和引用体系的使用详解》:本文主要介绍Java资源管理和引用体系的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Java的引用体系1、强引用 (Strong Reference)2、软引用 (Soft Reference)3、弱引用 (W