应用场景

现在由于前后端技术的分离,后端程序员在使用ORM框架开发后台API接口的时候,往往会将数据库的“数据模型”直接提供给前端。而大多数时候,可能这些数据并不能够满足前端展示的需求,有时候可能需要在“数据模型”的基础上,加几个字段或者改几个字段展示名称或者字段展示风格,以满足前端“视图模型”的需求。遇到这种情况,后端往往需要同时定义“数据模型”和“视图模型”,并在两者之间做大量的字段赋值工作,如果“数据模型”和“视图模型”差别不大的话,这无疑很耗费心力,而且容易出错。

我们先来理解两个概念“数据模型”和“视图模型”:

“数据模型”:最简单的一种“”数据模型“”你可以把它当成是数据库表对象模型(数据模型字段一一对应数据库表结构,是数据库表的一种表现形式),使用ORM的小伙伴应该都知道,通过ORM数据库模型可以直接映射到数据表结构,可以直接操作数据库。

“视图模型”:通过这个名称我们很容易理解,视图模型是前端展示页面中所需元素的一个集合。

当我们将“数据模型”转换成“视图模型”提供给前端的时候,务必会产生大量的模型字段赋值的工作,模型很大的时候是不是想死的心都有了。。。AutoMapper的出现正是解决了两个模型之间枯燥无味的转换工作,用户只需要简单设置一下转换规则即可,避免了我们每次都采用手工编写代码的方式进行转换。

.NetCore快速上手

1.创建项目

添加数据库“数据模型”:

  1. /// <summary>
  2. /// 订单表
  3. /// </summary>
  4. public class Order
  5. {
  6. /// <summary>
  7. /// ID
  8. /// </summary>
  9. public int Id { get; set; }
  10. /// <summary>
  11. /// 订单名称
  12. /// </summary>
  13. public string Name { get; set; }
  14. /// <summary>
  15. /// 价格
  16. /// </summary>
  17. public decimal Price { get; set; }
  18.  
  19. public DateTime CreateTime { get; set; }
  20.  
  21. public int CustomId { get; set; }
    }
  1. /// <summary>
  2. /// 订单子表
  3. /// </summary>
  4. public class OrderItem
  5. {
  6. public int ItemId { get; set; }
  7. public int OrderId { get; set; }
  8. public decimal Price { get; set; }
  9. /// <summary>
  10. /// 创建时间
  11. /// </summary>
  12. public DateTime CreateTime { get; set; }
  13. }

2.添加AutoMapper依赖包

第二个包是.NetCore依赖注入使用。

3.项目中添加“视图模型”

  1. /// <summary>
  2. /// 订单映射模型
  3. /// </summary>
  4. public class OrderDTO
  5. {
  6. public int Id { get; set; }
  7. /// <summary>
  8. /// 订单名称
  9. /// </summary>
  10. public string OrderName { get; set; }
  11. public decimal Price { get; set; }
  12. public DateTime CreateTime { get; set; }
  13. public int CustomId { get; set; }
  14. }
  1. /// <summary>
  2. /// 订单子表映射模型
  3. /// </summary>
  4. public class OrderItemDTO
  5. {
  6. public int ItemId { get; set; }
  7. public int OrderId { get; set; }
  8. public decimal Price { get; set; }
  9. /// <summary>
  10. /// 创建时间
  11. /// </summary>
  12. public string CreateTime { get; set; }
  13. }

4.添加自定义AutoMapper映射文件(OrderMapperProfile)

在.NetCore我们需要创建一个自己的映射配置类,该配置类必须继承AutoMapper的Profile抽象类,然后才能通过依赖注入AutoMapper的方式调用。

  1. /// <summary>
  2. /// 映射配置
  3. /// </summary>
  4. public class OrderMapperProfile : Profile
  5. {
  6. public OrderMapperProfile()
  7. {
  8. //字段名称不一致 Name映射到OrderName
  9. CreateMap<Order, OrderDTO>().ForMember(dest => dest.OrderName, src => src.MapFrom(s => s.Name));
  10. //字段类型不一致 DateTime映射到String
  11. CreateMap<OrderItem, OrderItemDTO>().ForMember(dest => dest.CreateTime, src => src.ConvertUsing(new FormatConvert()));
  12. }
  13. }
  14.  
  15. /// <summary>
  16. /// DateTime映射到String
  17. /// </summary>
  18. public class FormatConvert : IValueConverter<DateTime, string>
  19. {
  20. public string Convert(DateTime sourceMember, ResolutionContext context)
  21. {
  22. if (sourceMember == null)
  23. return DateTime.Now.ToString("yyyyMMddHHmmssfff");
  24. return sourceMember.ToString("yyyyMMddHHmmssfff");
  25. }
  26. }

1)自定义映射文件需继承AutoMapper抽象类“Profile”

2)调用方法CreateMap实现模型映射

  1. public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>(MemberList memberList);
  2. public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>();

TSource代表“数据模型”,TDestination代表“视图模型”,MemberList可选,默认0

  1. public enum MemberList
  2. {
  3. /// <summary>
  4. /// 检查是否已映射所有目标成员
  5. /// </summary>
  6. Destination = 0,
  7.  
  8. /// <summary>
  9. /// 检查是否已映射所有源成员
  10. /// </summary>
  11. Source = 1,
  12.  
  13. /// <summary>
  14. /// 既不检查源成员也不检查目标成员,跳过验证
  15. /// </summary>
  16. None = 2
  17. }

例如:

  1. CreateMap<Order, OrderDTO>();

3)调用ForMember自定义两个模型之间映射规则。

因为 AutoMapper 默认是通过匹配字段名称和类型进行自动匹配,所以如果你进行转换的两个类的中的某些字段名称不一样,这里我们就需要进行手动的编写转换规则。

  1. IMappingExpression<TSource, TDestination> ForMember<TMember>(Expression<Func<TDestination, TMember>> destinationMember, Action<IMemberConfigurationExpression<TSource, TDestination, TMember>> memberOptions);

其中比较常用的:

1.两个映射模型属性/字段名称不一致。

  1. //字段名称不一致 源类型Name映射到目标类型OrderName
  2. CreateMap<Order, OrderDTO>().ForMember(dest => dest.OrderName, src => src.MapFrom(s => s.Name));

2.两个映射模型属性/字段数据类型或展现形式不一致。

  1. //字段类型不一致 源类型DateTime映射到目标类型String字符串
  2. CreateMap<OrderItem, OrderItemDTO>().ForMember(dest => dest.CreateTime, src => src.ConvertUsing(new FormatConvert()));

ConvertUsing()方法中需实现成员参数接口IValueConverter中的Convert方法,实现自定义转换

  1. void ConvertUsing<TSourceMember>(IValueConverter<TSourceMember, TMember> valueConverter);
  1. public interface IValueConverter<in TSourceMember, out TDestinationMember>
  2. {
  3. TDestinationMember Convert(TSourceMember sourceMember, ResolutionContext context);
  4. }

自定义实现接口Convert方法,实现DateTime转string字符串:

  1. /// <summary>
  2. /// DateTime映射到String
  3. /// </summary>
  4. public class FormatConvert : IValueConverter<DateTime, string>
  5. {
  6. public string Convert(DateTime sourceMember, ResolutionContext context)
  7. {
  8. if (sourceMember == null)
  9. return DateTime.Now.ToString("yyyyMMddHHmmssfff");
  10. return sourceMember.ToString("yyyyMMddHHmmssfff");
  11. }
  12. }

5.配置好映射文件后,.NetCore中需要注册我们刚才的自定义Profile

  1. //注册AutoMapper
  2. //方式1 指定映射配置文件 多个可用数组表示
  3. services.AddAutoMapper(typeof(OrderMapperProfile));
  4. //方式2 注册程序集下面所有映射文件
  5. services.AddAutoMapper(Assembly.Load("程序集dll名称"))

6.最后我们可以通过注入AutoMapper的方式,在业务逻辑层使用我们的自定义映射配置文件Profile

  1. public class OrderService : IOrderService
  2. {
  3. private readonly IMapper mapper;
  4. /// <summary>
  5. /// 构造函数注入Mapper
  6. /// </summary>
  7. /// <param name="_dBContext"></param>
  8. /// <param name="_mapper"></param>
  9. public OrderService(IMapper _mapper)
  10. {
  11. mapper = _mapper;
  12. }
  13. /// <summary>
  14. /// 名称不一致 映射
  15. /// </summary>
  16. /// <returns></returns>
  17. public async Task<List<OrderDTO>> Query()
  18. {
  19. //ORM获取数据模型数据
  20. var orderList = await dBContext.DB.Queryable<Order>().ToListAsync();
  21. //DTO映射
  22. var orderDtoList = mapper.Map<List<OrderDTO>>(orderList);
  23. return await Task.FromResult(orderDtoList);
  24. }
  25.  
  26. /// <summary>
  27. /// 数据类型/展现形式不一致 映射
  28. /// </summary>
  29. /// <returns></returns>
  30. public async Task<List<OrderItemDTO>> QueryItem()
  31. {
  32. var orderList = await dBContext.DB.Queryable<OrderItem>().ToListAsync();
  33. var orderDtoList = mapper.Map<List<OrderItemDTO>>(orderList);
  34. return await Task.FromResult(orderDtoList);
  35. }
  36. }

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基础篇的更多相关文章

  1. Asp.NetCore之AutoMapper进阶篇

    应用场景 在上一篇文章--Asp.NetCore之AutoMapper基础篇中我们简单介绍了一些AutoMapper的基础用法以及如何在.NetCore中实现快速开发.我相信用过AutoMapper实 ...

  2. ASP.NET Web API 基础篇1

    ASP.NET Web API 直到我膝盖中了一箭[1]基础篇 无题 蓦然回首,那些年,我竟然一直很二. 小时候,读武侠小说的时候,看到那些猪脚,常常会产生一种代入感,幻想自己也会遭遇某种奇遇,遇到悬 ...

  3. AutoMapper在asp.netcore中的使用

    # AutoMapper在asp.netcore中的使用  automapper 是.net 项目中针对模型之间转换映射的一个很好用的工具,不仅提高了开发的效率还使代码更加简洁,当然也是开源的,htt ...

  4. .net 开源模板引擎jntemplate 教程:基础篇之在ASP.NET MVC中使用Jntemplate

    在ASP.NET MVC 中使用Jntemplate 上一篇我们详细介绍了jntemplate的标签语法,本篇文章将继续介绍如何在ASP.NET MVC 中使用Jntemplate. 一.使用Jnte ...

  5. Asp.Net Core基础篇之:白话管道中间件

    在Asp.Net Core中,管道往往伴随着请求一起出现.客户端发起Http请求,服务端去响应这个请求,之间的过程都在管道内进行. 举一个生活中比较常见的例子:旅游景区. 我们都知道,有些景区大门离景 ...

  6. 壹佰文章最全总结| 《关于ASP.NETCore的分享之路》

    学习路线图 (关于学习ASP.NET Core需要了解和掌握的知识点图) 一言不合就来图,各位博客园小伙伴大家好,感觉好久没有写文章了,自从春节开始,中间经历种种,慢慢的就开始微信公众号发文了,原因有 ...

  7. Asp.NetCore之组件写法

    本章内容和大家分享的是Asp.NetCore组件写法,在netcore中很多东西都以提供组件的方式来使用,比如MVC架构,Session,Cache,数据库引用等: 这里我也通过调用验证码接口来自定义 ...

  8. Asp.NetCore轻松学-使用Supervisor进行托管部署

    前言 上一篇文章 Asp.NetCore轻松学-部署到 Linux 进行托管 介绍了如何在 Centos 上部署自托管的 .NET Core 应用程序,接下来的内容就是介绍如何使用第三方任务管理程序来 ...

  9. Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(二)

    Asp.NetCore程序发布到CentOs(含安装部署netcore)--最佳实践(一) 接上一篇 3. Nginx配置反向代理 3.1 cnetos 安装nginx 首先,我们需要在服务器上安装N ...

随机推荐

  1. Union-Find算法详解

    今天讲讲 Union-Find 算法,也就是常说的并查集算法,主要是解决图论中「动态连通性」问题的.名词很高端,其实特别好理解,等会解释,另外这个算法的应用都非常有趣. 说起这个 Union-Find ...

  2. flex与bison的学习

    获取bison http://www.gnu.org/software/bison 获取flex http://flex.sourceforge.net/ 本书的范例 ftp://ftp.iecc.c ...

  3. day85:luffy:购物车根据有效期不同切换价格&购物车删除操作&价格结算&订单页面前戏

    目录 1.购物车有效期切换 2.根据有效期不同切换价格 3.购物车删除操作 4.价格结算 5.订单页面-初始化 1.购物车有效期切换 1.关于有效期表结构的设计 1.course/models.py ...

  4. 【SpringBoot】11-1.Springboot整合Springmvc+Mybatis增删改查操作(下)

    整合过程:https://www.isdxh.com/68.html 一.增--增加用户 1.创建实体类 package com.dxh.pojo; public class Users { priv ...

  5. 看得见的成本!1款工具实现K8S资源成本监控可视化

    本文来自Rancher Labs 关注我们,第一时间获取技术干货 计算Kubernetes成本的复杂性 采用Kubernetes和基于服务的架构可以为企业带来诸多好处,如团队可以更快地迁移以及应用程序 ...

  6. Python基本数据类型与数据结构(数据挖掘学习)

    前言 最近工作和研究涉及到数据挖掘和机器学习,出于归纳和总结知识的目的写下这一系列的文章,这一系列文章将会包括Python的基本数据类型和数据结构,函数和面向对象相关的知识,然后会介绍数据挖掘和机器学 ...

  7. layui表单提交与ajax访问webapi

    啊啊啊啊 这个东西实在很蛋疼啊 每次访问webapi就很老火 这里就一下  以后忘记的话就来查阅 不多说 直接开始 首先html页面 新建一个基于layui的form表单页面LayuiForm.csh ...

  8. NIO源码分析:SelectionKey

    SelectionKey SelectionKey,选择键,在每次通道注册到选择器上时都会创建一个SelectionKey储存在该选择器上,该SelectionKey保存了注册的通道.注册的选择器.通 ...

  9. <摘自>飞:jxl简析2 [ http://www.emlog.net/fei ]

    [<摘自>飞:jxl简析:http://www.emlog.net/fei] (二)应用 在进行实践前 , 我们需要对 excel 有一个大致的了解 ,excel 文件由一个工作簿 (Wo ...

  10. java里split(" {1,}")什么意思啊?

    将字符串按照括号内的内容分割成字符数组这里括号内是正则表达式,X{m,n}代表X至少重复m次,至多重复n次这里空格至少重复1次,就是将字符串以一个或多个空格分割如"1 2 ab c" ...