Asp.NetCore之AutoMapper基础篇
应用场景
现在由于前后端技术的分离,后端程序员在使用ORM框架开发后台API接口的时候,往往会将数据库的“数据模型”直接提供给前端。而大多数时候,可能这些数据并不能够满足前端展示的需求,有时候可能需要在“数据模型”的基础上,加几个字段或者改几个字段展示名称或者字段展示风格,以满足前端“视图模型”的需求。遇到这种情况,后端往往需要同时定义“数据模型”和“视图模型”,并在两者之间做大量的字段赋值工作,如果“数据模型”和“视图模型”差别不大的话,这无疑很耗费心力,而且容易出错。
我们先来理解两个概念“数据模型”和“视图模型”:
“数据模型”:最简单的一种“”数据模型“”你可以把它当成是数据库表对象模型(数据模型字段一一对应数据库表结构,是数据库表的一种表现形式),使用ORM的小伙伴应该都知道,通过ORM数据库模型可以直接映射到数据表结构,可以直接操作数据库。
“视图模型”:通过这个名称我们很容易理解,视图模型是前端展示页面中所需元素的一个集合。
当我们将“数据模型”转换成“视图模型”提供给前端的时候,务必会产生大量的模型字段赋值的工作,模型很大的时候是不是想死的心都有了。。。AutoMapper的出现正是解决了两个模型之间枯燥无味的转换工作,用户只需要简单设置一下转换规则即可,避免了我们每次都采用手工编写代码的方式进行转换。
.NetCore快速上手
1.创建项目
添加数据库“数据模型”:
/// <summary>
/// 订单表
/// </summary>
public class Order
{
/// <summary>
/// ID
/// </summary>
public int Id { get; set; }
/// <summary>
/// 订单名称
/// </summary>
public string Name { get; set; }
/// <summary>
/// 价格
/// </summary>
public decimal Price { get; set; } public DateTime CreateTime { get; set; } public int CustomId { get; set; }
}
/// <summary>
/// 订单子表
/// </summary>
public class OrderItem
{
public int ItemId { get; set; }
public int OrderId { get; set; }
public decimal Price { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public DateTime CreateTime { get; set; }
}
2.添加AutoMapper依赖包
第二个包是.NetCore依赖注入使用。
3.项目中添加“视图模型”
/// <summary>
/// 订单映射模型
/// </summary>
public class OrderDTO
{
public int Id { get; set; }
/// <summary>
/// 订单名称
/// </summary>
public string OrderName { get; set; }
public decimal Price { get; set; }
public DateTime CreateTime { get; set; }
public int CustomId { get; set; }
}
/// <summary>
/// 订单子表映射模型
/// </summary>
public class OrderItemDTO
{
public int ItemId { get; set; }
public int OrderId { get; set; }
public decimal Price { get; set; }
/// <summary>
/// 创建时间
/// </summary>
public string CreateTime { get; set; }
}
4.添加自定义AutoMapper映射文件(OrderMapperProfile)
在.NetCore我们需要创建一个自己的映射配置类,该配置类必须继承AutoMapper的Profile抽象类,然后才能通过依赖注入AutoMapper的方式调用。
/// <summary>
/// 映射配置
/// </summary>
public class OrderMapperProfile : Profile
{
public OrderMapperProfile()
{
//字段名称不一致 Name映射到OrderName
CreateMap<Order, OrderDTO>().ForMember(dest => dest.OrderName, src => src.MapFrom(s => s.Name));
//字段类型不一致 DateTime映射到String
CreateMap<OrderItem, OrderItemDTO>().ForMember(dest => dest.CreateTime, src => src.ConvertUsing(new FormatConvert()));
}
} /// <summary>
/// DateTime映射到String
/// </summary>
public class FormatConvert : IValueConverter<DateTime, string>
{
public string Convert(DateTime sourceMember, ResolutionContext context)
{
if (sourceMember == null)
return DateTime.Now.ToString("yyyyMMddHHmmssfff");
return sourceMember.ToString("yyyyMMddHHmmssfff");
}
}
1)自定义映射文件需继承AutoMapper抽象类“Profile”
2)调用方法CreateMap实现模型映射
public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>(MemberList memberList);
public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>();
TSource代表“数据模型”,TDestination代表“视图模型”,MemberList可选,默认0
public enum MemberList
{
/// <summary>
/// 检查是否已映射所有目标成员
/// </summary>
Destination = 0, /// <summary>
/// 检查是否已映射所有源成员
/// </summary>
Source = 1, /// <summary>
/// 既不检查源成员也不检查目标成员,跳过验证
/// </summary>
None = 2
}
例如:
CreateMap<Order, OrderDTO>();
3)调用ForMember自定义两个模型之间映射规则。
因为 AutoMapper 默认是通过匹配字段名称和类型进行自动匹配,所以如果你进行转换的两个类的中的某些字段名称不一样,这里我们就需要进行手动的编写转换规则。
IMappingExpression<TSource, TDestination> ForMember<TMember>(Expression<Func<TDestination, TMember>> destinationMember, Action<IMemberConfigurationExpression<TSource, TDestination, TMember>> memberOptions);
其中比较常用的:
1.两个映射模型属性/字段名称不一致。
//字段名称不一致 源类型Name映射到目标类型OrderName
CreateMap<Order, OrderDTO>().ForMember(dest => dest.OrderName, src => src.MapFrom(s => s.Name));
2.两个映射模型属性/字段数据类型或展现形式不一致。
//字段类型不一致 源类型DateTime映射到目标类型String字符串
CreateMap<OrderItem, OrderItemDTO>().ForMember(dest => dest.CreateTime, src => src.ConvertUsing(new FormatConvert()));
ConvertUsing()方法中需实现成员参数接口IValueConverter中的Convert方法,实现自定义转换
void ConvertUsing<TSourceMember>(IValueConverter<TSourceMember, TMember> valueConverter);
public interface IValueConverter<in TSourceMember, out TDestinationMember>
{
TDestinationMember Convert(TSourceMember sourceMember, ResolutionContext context);
}
自定义实现接口Convert方法,实现DateTime转string字符串:
/// <summary>
/// DateTime映射到String
/// </summary>
public class FormatConvert : IValueConverter<DateTime, string>
{
public string Convert(DateTime sourceMember, ResolutionContext context)
{
if (sourceMember == null)
return DateTime.Now.ToString("yyyyMMddHHmmssfff");
return sourceMember.ToString("yyyyMMddHHmmssfff");
}
}
5.配置好映射文件后,.NetCore中需要注册我们刚才的自定义Profile
//注册AutoMapper
//方式1 指定映射配置文件 多个可用数组表示
services.AddAutoMapper(typeof(OrderMapperProfile));
//方式2 注册程序集下面所有映射文件
services.AddAutoMapper(Assembly.Load("程序集dll名称"))
6.最后我们可以通过注入AutoMapper的方式,在业务逻辑层使用我们的自定义映射配置文件Profile
public class OrderService : IOrderService
{
private readonly IMapper mapper;
/// <summary>
/// 构造函数注入Mapper
/// </summary>
/// <param name="_dBContext"></param>
/// <param name="_mapper"></param>
public OrderService(IMapper _mapper)
{
mapper = _mapper;
}
/// <summary>
/// 名称不一致 映射
/// </summary>
/// <returns></returns>
public async Task<List<OrderDTO>> Query()
{
//ORM获取数据模型数据
var orderList = await dBContext.DB.Queryable<Order>().ToListAsync();
//DTO映射
var orderDtoList = mapper.Map<List<OrderDTO>>(orderList);
return await Task.FromResult(orderDtoList);
} /// <summary>
/// 数据类型/展现形式不一致 映射
/// </summary>
/// <returns></returns>
public async Task<List<OrderItemDTO>> QueryItem()
{
var orderList = await dBContext.DB.Queryable<OrderItem>().ToListAsync();
var orderDtoList = mapper.Map<List<OrderItemDTO>>(orderList);
return await Task.FromResult(orderDtoList);
}
}
7.实现效果
1)“数据模型”Order类型中的Name属性值 映射到 “视图模型”OrderDTO类型中的OrderName
2)“数据模型”OrderItem类型中的CreateTime属性DateTime数据类型 映射到 “视图模型”OrderItemDTO类型中的CreateTime属性string数据类型
小结
本篇文章主要简单介绍下在Asp.NetCore项目中如何快速上手AutoMapper,总体来看想要上手还是比较简单,只要掌握好几个经常使用的映射规则就可以了。当然,AutoMapper为我们准备了各种自定规则的入口,有兴趣的小伙伴可以下载源码,源码中包含了很多测试用例,学习起来也比较容易理解。附上AutoMapper源码地址:https://github.com/AutoMapper/AutoMapper
Asp.NetCore之AutoMapper基础篇的更多相关文章
- Asp.NetCore之AutoMapper进阶篇
应用场景 在上一篇文章--Asp.NetCore之AutoMapper基础篇中我们简单介绍了一些AutoMapper的基础用法以及如何在.NetCore中实现快速开发.我相信用过AutoMapper实 ...
- ASP.NET Web API 基础篇1
ASP.NET Web API 直到我膝盖中了一箭[1]基础篇 无题 蓦然回首,那些年,我竟然一直很二. 小时候,读武侠小说的时候,看到那些猪脚,常常会产生一种代入感,幻想自己也会遭遇某种奇遇,遇到悬 ...
- AutoMapper在asp.netcore中的使用
# AutoMapper在asp.netcore中的使用 automapper 是.net 项目中针对模型之间转换映射的一个很好用的工具,不仅提高了开发的效率还使代码更加简洁,当然也是开源的,htt ...
- .net 开源模板引擎jntemplate 教程:基础篇之在ASP.NET MVC中使用Jntemplate
在ASP.NET MVC 中使用Jntemplate 上一篇我们详细介绍了jntemplate的标签语法,本篇文章将继续介绍如何在ASP.NET MVC 中使用Jntemplate. 一.使用Jnte ...
- Asp.Net Core基础篇之:白话管道中间件
在Asp.Net Core中,管道往往伴随着请求一起出现.客户端发起Http请求,服务端去响应这个请求,之间的过程都在管道内进行. 举一个生活中比较常见的例子:旅游景区. 我们都知道,有些景区大门离景 ...
- 壹佰文章最全总结| 《关于ASP.NETCore的分享之路》
学习路线图 (关于学习ASP.NET Core需要了解和掌握的知识点图) 一言不合就来图,各位博客园小伙伴大家好,感觉好久没有写文章了,自从春节开始,中间经历种种,慢慢的就开始微信公众号发文了,原因有 ...
- Asp.NetCore之组件写法
本章内容和大家分享的是Asp.NetCore组件写法,在netcore中很多东西都以提供组件的方式来使用,比如MVC架构,Session,Cache,数据库引用等: 这里我也通过调用验证码接口来自定义 ...
- Asp.NetCore轻松学-使用Supervisor进行托管部署
前言 上一篇文章 Asp.NetCore轻松学-部署到 Linux 进行托管 介绍了如何在 Centos 上部署自托管的 .NET Core 应用程序,接下来的内容就是介绍如何使用第三方任务管理程序来 ...
- Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(二)
Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一) 接上一篇 3. Nginx配置反向代理 3.1 cnetos 安装nginx 首先,我们需要在服务器上安装N ...
随机推荐
- Python爬虫之线程池
详情点我跳转 关注公众号"轻松学编程"了解更多. 一.为什么要使用线程池? 对于任务数量不断增加的程序,每有一个任务就生成一个线程,最终会导致线程数量的失控,例如,整站爬虫,假设初 ...
- python实现类的多态
多态 关注公众号"轻松学编程"了解更多. 1.多态使用 一种事物的多种体现形式,举例:动物有很多种 注意: 继承是多态的前提 函数重写就是多态的体现形式 演示:重写Animal类 ...
- Nginx是什么?有什么用?
一.Nginx是什么 Nginx ("engine x") 是一个高性能的 HTTP 和反向代理服务器,特点是占有内存少,并发能力强,事实上nginx的并发能力确实在同类型的网页服 ...
- 红帽6.9搭建yum源的2种方式(HTTP和本地)
方式一:HTTP搭建 1.首先删除本身所带的yum `rpm -qa | grep yum | xargs rpm -e --nodeps ` #忽略依赖关系,强行删除 若出现 错误出现 将后面的 ...
- 微服务网关Zuul和Gateway的区别
spring-cloud-Gateway是spring-cloud的一个子项目.而zuul则是netflix公司的项目,只是spring将zuul集成在spring-cloud中使用而已.因为zuul ...
- 《Web接口开发与自动化测试》学习笔记(三)
一.认证系统 使用django本身自带的认证系统 1.登录admin后台 1. 先建立一个管理员用户: > python manage.py creatsuperuser 输入用户名.邮箱和密码 ...
- 全排列算法--递归实现(Java)
求一个n阶行列式,一个比较简单的方法就是使用全排列的方法,那么简述以下全排列算法的递归实现. 首先举一个简单的例子说明算法的原理,既然是递归,首先说明一下出口条件.以[1, 2]为例 首先展示一下主要 ...
- C++ 数据结构 2:栈和队列
1 栈 1.1 栈的基本概念 栈(stack)又名堆栈,它是一种 运算受限的线性表.限定 仅在表尾进行插入和删除操作 的线性表.表尾被称为栈顶,相对地,把另一端称为栈底. 1.1.1 特点 它的特殊之 ...
- 1redis介绍
一,概述 是一种nosql数据库,保存在内存中,同时redis可以把内存同时保存到磁盘,即可以把数据持久化.支持较多的数据类型,string,list(队列和栈),set,sorted set,has ...
- Socket accept 简要分析
accept 用于从指定套接字的连接队列中取出第一个连接,并返回一个新的套接字用于与客户端进行通信,示例代码如下 #include <sys/types.h> /* See NOTES * ...