应用场景

现在由于前后端技术的分离,后端程序员在使用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基础篇的更多相关文章

  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. Django之富文本(获取内容,设置内容)

    富文本 1.Rich Text Format(RTF) 微软开发的跨平台文档格式,大多数的文字处理软件都能读取和保存RTF文档,其实就是可以添加样式的文档,和HTML有很多相似的地方 图示 2.tin ...

  2. 833. Find And Replace in String —— weekly contest 84

    Find And Replace in String To some string S, we will perform some replacement operations that replac ...

  3. mysql处理查询请求的步骤

    服务端处理客户端的查询请求大致需要三个步骤: 连接管理 客户端连接服务端时,服务端会为其分配一个线程,客户端断开连接不会回收线程(避免频繁创建销毁的性能问题),服务端一直等待客户端发来消息(文本消息) ...

  4. 细学C++之C++语言的特点

    优点: 1.强大的抽象封装能力:这让C++语言具备了强大的开发工程能力 2.高性能:运行快,并且占用资源少 3.低功耗:适合在各种微型的嵌入式设备中运行高效的程序 缺点: 1.语法相对复杂,细节比较多 ...

  5. 【SpringBoot】05.SpringBoot整合Listener的两种方式

    SpringBoot整合Listener的两种方式: 1.通过注解扫描完成Listener组件的注册 创建一个类实现ServletContextListener (具体实现哪个Listener根据情况 ...

  6. python爬虫04 Requests

    接下来我们要来玩一个新的库 这个库的名称叫做 Requests 这个库比我们上次说的 urllib 可是要牛逼一丢丢的 毕竟 Requests 是在 urllib 的基础上搞出来的 通过它我们可以用更 ...

  7. 获取url后面的参数

    function getQueryVariable(variable) { var query = window.location.search.substring(1); var vars = qu ...

  8. linux 信号 ctrl + d z c fg bg 作用

    ctrl+c:前台进程终止 后台进程的终止: 方法一:通过jobs命令查看job号(假设为num),然后执行kill %num   $ kill %1 方法二:通过ps命令查看job的进程号(PID, ...

  9. FreeSql接入CAP的实践

    CAP CAP 是一个基于 .NET Standard 的 C# 库,它是一种处理分布式事务的解决方案,同样具有 EventBus 的功能,它具有轻量级.易使用.高性能等特点. https://git ...

  10. rbd的image快照与Pool快照

    前言 这个问题是不久前在ceph社区群里看到的,创建image的时候,当时的报错如下: 2016-12-13 23:13:10.266865 7efbfb7fe700 -1 librbd::image ...