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

相关文章

Spring IoC 容器的使用详解(最新整理)

《SpringIoC容器的使用详解(最新整理)》文章介绍了Spring框架中的应用分层思想与IoC容器原理,通过分层解耦业务逻辑、数据访问等模块,IoC容器利用@Component注解管理Bean... 目录1. 应用分层2. IoC 的介绍3. IoC 容器的使用3.1. bean 的存储3.2. 方法注

Python内置函数之classmethod函数使用详解

《Python内置函数之classmethod函数使用详解》:本文主要介绍Python内置函数之classmethod函数使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 类方法定义与基本语法2. 类方法 vs 实例方法 vs 静态方法3. 核心特性与用法(1编程客

Linux中压缩、网络传输与系统监控工具的使用完整指南

《Linux中压缩、网络传输与系统监控工具的使用完整指南》在Linux系统管理中,压缩与传输工具是数据备份和远程协作的桥梁,而系统监控工具则是保障服务器稳定运行的眼睛,下面小编就来和大家详细介绍一下它... 目录引言一、压缩与解压:数据存储与传输的优化核心1. zip/unzip:通用压缩格式的便捷操作2.

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

Python中注释使用方法举例详解

《Python中注释使用方法举例详解》在Python编程语言中注释是必不可少的一部分,它有助于提高代码的可读性和维护性,:本文主要介绍Python中注释使用方法的相关资料,需要的朋友可以参考下... 目录一、前言二、什么是注释?示例:三、单行注释语法:以 China编程# 开头,后面的内容为注释内容示例:示例:四

Go语言数据库编程GORM 的基本使用详解

《Go语言数据库编程GORM的基本使用详解》GORM是Go语言流行的ORM框架,封装database/sql,支持自动迁移、关联、事务等,提供CRUD、条件查询、钩子函数、日志等功能,简化数据库操作... 目录一、安装与初始化1. 安装 GORM 及数据库驱动2. 建立数据库连接二、定义模型结构体三、自动迁

ModelMapper基本使用和常见场景示例详解

《ModelMapper基本使用和常见场景示例详解》ModelMapper是Java对象映射库,支持自动映射、自定义规则、集合转换及高级配置(如匹配策略、转换器),可集成SpringBoot,减少样板... 目录1. 添加依赖2. 基本用法示例:简单对象映射3. 自定义映射规则4. 集合映射5. 高级配置匹

Spring 框架之Springfox使用详解

《Spring框架之Springfox使用详解》Springfox是Spring框架的API文档工具,集成Swagger规范,自动生成文档并支持多语言/版本,模块化设计便于扩展,但存在版本兼容性、性... 目录核心功能工作原理模块化设计使用示例注意事项优缺点优点缺点总结适用场景建议总结Springfox 是

嵌入式数据库SQLite 3配置使用讲解

《嵌入式数据库SQLite3配置使用讲解》本文强调嵌入式项目中SQLite3数据库的重要性,因其零配置、轻量级、跨平台及事务处理特性,可保障数据溯源与责任明确,详细讲解安装配置、基础语法及SQLit... 目录0、惨痛教训1、SQLite3环境配置(1)、下载安装SQLite库(2)、解压下载的文件(3)、

使用Python绘制3D堆叠条形图全解析

《使用Python绘制3D堆叠条形图全解析》在数据可视化的工具箱里,3D图表总能带来眼前一亮的效果,本文就来和大家聊聊如何使用Python实现绘制3D堆叠条形图,感兴趣的小伙伴可以了解下... 目录为什么选择 3D 堆叠条形图代码实现:从数据到 3D 世界的搭建核心代码逐行解析细节优化应用场景:3D 堆叠图