AutoMapper入门使用

在应用开发的过程中,首先要了解整个系统中各个系统的组件的作用,然后了解系统的工作流(workflow),最后需要梳理一遍数据流(dataflow),而在整理数据流的过程中,数据的转化常常是最难理解写起来相当枯燥乏味的部分,AutoMapper的功能就是实现映射一个对象到另一个对象的自动化工具,最常见的就是DTO (Data Transfer Object)与MO(ModelObject)之间的转换,这里我先介绍一下DTO与MO的关系,然后才介绍AutoMapper工具的使用。

理解DTO

以下是我总结的几个不同平台的解释:

    • 百度百科:

数据传输对象(DTO)(Data Transfer Object),是一种设计模式之间传输数据的软件应用系统。数据传输目标往往是数据访问对象从数据库中检索数据。数据传输对象与数据交互对象或数据访问对象之间的差异是一个以不具有任何行为除了存储和检索的数据(访问和存取器)

    • 维基百科:

数据传输对象(DTO)是在两个进程之间承载数据的对象。数据传输和业务对象或数据访问对象之间的区别在于,DTO除了存储和检索其自身的数据(调制器和访问器)之外没有任何行为。DTO是不应该包含任何需要测试的业务逻辑的简单对象。

    • 博客园dax.net:

表现层于应用层之间是通过DTO来进行交互的,数据传输对象是没有行为的POCO对象,他的目的是为了对领域对象进行数据封装,实现层与层之间的数据传递。简单来说Model面向业务,我们是通过业务来定义Model的。而DTO是面向UI,通过UI的需求来定义的,通过DTO我们实现了表现层与Model层之间的解耦,表现层不引用Model。如果开发过程中我们的模型变了,而界面没变,我们只需改Model而不需要去改动表现层。

看了这些解释,应该还是有点蒙?

先来看看为什么要使用DTO,我总结了三点

    • 隔离领域模型,使用封装(包括数据结构的精简和合并)的DTO实现改动领域模型而不影响UI,保持领域模型的安全,不暴露业务逻辑。
    • 在分布式模式下,相同的数据结构在不同的场景使用相同的数据结构有不同的需求。
    • DTO的存在也为了帮助减少客户端请求而降低服务器压力,提升效率。

种,非常难于管理,当页面所需要的数据与数据库中的数据不一致的情况如果常常出现,那么我们就需要开始着手准备添加对DTO的支持,并且DTO可以设当的冗余设计来减少DTO种类

在系统中添加DTO主要有以下几部分工作需要完成

    • 设计和添加DTO类。
    • 添加从MO到DTO的转化逻辑。
    • 将原本对MO的使用转换为对DTO的使用。(这里可以看出,要尽早的预判是否需要DTO,以免将来麻烦)

关于DTO就了解到这,下面开始回归正题,介绍AutoMapper工具的使用

AutoMapper入门

安装AutoMapper

    • 从包管理器控制台安装

打开程序包管理器控制台,然后输入命令:Install-Package AutoMapper

    • 从包管理器界面安装

在界面中搜索需要安装的程序集,如AutoMapper.dll

安装完成之后添加到程序集引用中即可。

如何使用AutoMapper

首先,您需要使用源类型和目标类型。目标类型的设计可能受其所在层的影响,但只要成员的名称与源类型的成员匹配,AutoMapper就可以发挥最佳效果。如果您有一个名为“FirstName”的源成员,它将自动映射到名称为“FirstName”的目标成员。AutoMapper也支持拼合。

一旦你有了你的类型,你可以使用MapperConfiguration或者静态Mapper实例和CreateMap为这两种类型创建一个映射。MapperConfiguration通常每个AppDomain只需要一个实例,并且应该在启动过程中实例化。

    • 创建映射的两种方式(左侧的类型是源类型,右侧的类型是目标类型):
    • 静态方式:
    • Mapper.Initialize(cfg => cfg.CreateMap<Order, OrderDto>());
    • 如果您使用的是静态Mapper方法,则每个AppDomain只能进行一次配置。这意味着放置配置代码的最佳位置是在应用程序启动时,例如ASP.NET应用程序的Global.asax文件
    • 实例方式
    • var config = new MapperConfiguration(cfg => cfg.CreateMap<Order, OrderDto>());

要执行映射又可以使用静态或实例映射器方法:

    • IMapper mapper = config.CreateMapper();
    • IMapper mapper = new Mapper(config);

大多数应用程序可以使用依赖注入来注入创建的IMapper实例。

    • 可以添加配置到配置类中,方便统一管理(AddProfile),然后通过自己写一下泛型返回自己想要的类型转换,这样可以一次性实例化多种类型映射:
    • Mapper.Initialize(cfg => cfg.AddProfile(new MyProfile()));
    • Mapper.Initialize(cfg => cfg.AddProfile<MyProfile>());
    • var config = new MapperConfiguration(fig => fig.AddProfile(new MyProfile()));
    • var config = new MapperConfiguration(fig => fig.AddProfile< MyProfile>());

处理下面几种情况的方式

属性名称相同

扁平化映射

投影(指定字段)

简单类型映射

使用Profile配置

属性名称不同

条件映射:

空值替换NullSubstitute

忽略属性Ignore

目标属性多于源属性,可以进行预设值

类型转换ITypeConverter

using AutoMapper;

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace AutoMapperDemo

{

public static class AutoMapperInitialize

{

static AutoMapperInitialize()

{

Mapper.Initialize(fig => fig.AddProfile<MyProfile>());

}

public class User

{

public int Id { set; get; }

public string Name { set; get; }

public int Age { set; get; }

public User(int i)

{

Id = i;

Name = "muphy-" + i;

Age = 15 + i;

}

public User()

{

Id = 1;

Name = "muphy";

Age = 15;

}

public override string ToString()

{

return "[Name:" + Name + ",Age:" + Age + "]";

}

}

public class UserDto

{

public string Name { set; get; }

public int Age { set; get; }

public override string ToString()

{

return "[Name:" + Name + ",Age:" + Age + "]";

}

}

public class Azi : User

{

public string Like { set; get; }

public Azi(int i) : base(i) { Like = "QiaoFeng"; }

public Azi() { }

public override string ToString()

{

return "[Name:" + Name + ",Age:" + Age + "]";

}

}

public class Product

{

public Supplier Supplier { set; get; }

public decimal GetPrice()

{

return 10;

}

public Product()

{

Supplier = new Supplier();

}

}

public class Supplier

{

public string Name { get; set; }

public Supplier()

{

Name = "伟创力";

}

}

public class ProductDto

{

public string SupplierName { set; get; }

public decimal Price { set; get; }

public override string ToString()

{

return "[Price:" + Price + ",SupplierName:" + SupplierName + "]";

}

}

public class Book : Product

{

public DateTime BuyTime { get { return DateTime.Now; } }

}

public class BookDto : ProductDto

{

public DateTime Date { get; set; }

public int Hour { get; set; }

public int Minute { get; set; }

public override string ToString()

{

return "[Price:" + Price + ",SupplierName:" + SupplierName + ",Date:" + Date + "]";

}

}

public class Source

{

public string Name { get { return "muphy"; } }

public int Width { set; get; }

}

public class Destination

{

public string Name { get; set; }

public string like { get; set; }

public override string ToString()

{

return Name + " Like " + like;

}

}

public class MyProfile : Profile

{

public MyProfile()

{

//类型字段系统

CreateMap<User, UserDto>();

//扁平化映射

CreateMap<Product, ProductDto>();

//投影

CreateMap<Book, BookDto>()

.ForMember(desc => desc.Date, opt => opt.MapFrom(src => src.BuyTime.Date))

.ForMember(desc => desc.Hour, opt => opt.MapFrom(src => src.BuyTime.Hour))

.ForMember(desc => desc.Minute, opt => opt.MapFrom(src => src.BuyTime.Minute));

// 条件映射

CreateMap<Azi, UserDto>().ForMember(desc => desc.Age, opt => opt.MapFrom(src => src.Age< 21));

// 可设置默认值

CreateMap<Source, Destination>().ForMember(desc => desc.like, opt => opt.MapFrom(src =>"azi"));

//可忽视多余值

CreateMap< Destination, Source>().ForMember(desc => desc.Width, opt => opt.Ignore());

//空值替换

CreateMap<Source, Destination>().ForMember(desc => desc.Name, opt =>opt.NullSubstitute("azi"));

//其他设置

CreateMap<User, Azi>()

.BeforeMap((src,desc) => src.Age += 50)

.AfterMap((src,desc)=>desc.Age -=  35)// 设置转换前后的行为

.ReverseMap();//设置反向映射

}

}

// 1.简单静态的方式初始化映射 使用Initialize 两个方法:CreateMap AddProfile(稍后)

public static UserDto AutoMapperConfig1()

{

//Mapper.Initialize(cfg => cfg.CreateMap<User, UserDto>());

//Mapper.Initialize(cfg => cfg.AddProfile(new MyProfile()));

//Mapper.Initialize(cfg => cfg.AddProfile<MyProfile>());

UserDto dto = Mapper.Map<UserDto>(new User(1));

return dto;

}

// 2.简单实例的方式初始化方式映射 使用MapperConfiguration  也有两种方式:CreateMapper方法和Mpapper构造函数

public static UserDto AutoMapperConfig2()

{

MapperConfiguration config = new MapperConfiguration(fig => fig.CreateMap<User, UserDto>());

var mapper = config.CreateMapper();

//IMapper mapper = new Mapper(config);

return mapper.Map<UserDto>(new User(2));

}

// 3.使用继承Profile的配置属性方式映射 AddProfile方法

public static UserDto AutoMapperConfig3()

{

MapperConfiguration config = new MapperConfiguration(fig => fig.AddProfile<MyProfile>());

IMapper mapper = new Mapper(config);

return mapper.Map<UserDto>(new User(3));

}

// 4.使用继承Profile的配置属性 + 泛型方式映射 效果会更好

public static T AutoMapperConfig4<K, T>(K k)

{

return Mapper.Map<T>(k);

}

// 5.扁平化映射

public static ProductDto AutoMapperConfig5()

{

MapperConfiguration config = new MapperConfiguration(fig => fig.AddProfile<MyProfile>());

var mapper = config.CreateMapper();

return mapper.Map<ProductDto>(new Product());

}

}

}

AutoMapper入门使用的更多相关文章

  1. AutoMapper之如何开始,适合入门和演示

    原来想应该介绍下背景说明下好处什么的,仔细想都是废话 ,直接上代码吧. 首先有两个类,一个是和数据库对应的实体 Student,一个是和页面展示相关的页面模型 StudentModel. /// &l ...

  2. 00.AutoMapper 之入门指南(Getting Started Guide)

    转载(https://www.jianshu.com/p/29ee5a94c1d9) 入门指南(Getting Started Guide) AutoMapper 是什么? AutoMapper 是一 ...

  3. Asp.net Core 2.2关于AutoMapper更初级的入门教程

    今天刚看到老张的哲学博客关于AutoMapper的教程,从壹开始前后端分离[ .NET Core2.0 +Vue2.0 ]框架之十三 || DTOs 对象映射使用,项目部署Windows+Linux完 ...

  4. ABP(现代ASP.NET样板开发框架)系列之2、ABP入门教程

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)” ...

  5. AutoMapper之ABP项目中的使用介绍

    最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMapper只要用来数据转换,在园里已经有很多 ...

  6. ABP入门系列(6)——展现层实现增删改查

    这一章节将通过完善Controller.View.ViewModel,来实现展现层的增删改查.最终实现效果如下图: 一.定义Controller ABP对ASP.NET MVC Controllers ...

  7. ABP入门系列(5)——创建应用服务

    一.解释下应用服务层 应用服务用于将领域(业务)逻辑暴露给展现层.展现层通过传入DTO(数据传输对象)参数来调用应用服务,而应用服务通过领域对象来执行相应的业务逻辑并且将DTO返回给展现层.因此,展现 ...

  8. 基于DDD的现代ASP.NET开发框架--ABP系列之2、ABP入门教程

    基于DDD的现代ASP.NET开发框架--ABP系列之2.ABP入门教程 ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boi ...

  9. ABP项目中的使用AutoMapper

    AutoMapper之ABP项目中的使用 最近在研究ABP项目,昨天写了Castle Windsor常用介绍以及其在ABP项目的应用介绍 欢迎各位拍砖,有关ABP的介绍请看阳光铭睿 博客 AutoMa ...

随机推荐

  1. Javascript异步编程之一异步原理

    本系列的例子主要针对node.js环境,但浏览器端的原理应该也是类似的. 本人也是Javascript新手,把自己这段时间学习积累的要点总结下来,希望可以对同样在学习Javascript/node.j ...

  2. CPP内存检测

    对C.C++的内存泄露.内存溢出等检查,经过这两天的查资料,总体来说可以使用Valgrind, AddressSanitizer, Dr.Memory等.其中Valgrind对程序运行速度影响较大,运 ...

  3. Android细笔记--DataStorage

    Shared Preferences 即使应用被杀了,shared preference也还是存在的 Internal Storage 创建于internal的文件只对本应用开放权限,即使手机用户本身 ...

  4. Android Camera2 预览功能实现

    1. 概述 最近在做一些关于人脸识别的项目,需要用到 Android 相机的预览功能.网上查阅相关资料后,发现 Android 5.0 及以后的版本中,原有的 Camera API 已经被 Camer ...

  5. Python高级应用(3)—— 为你的项目添加验证码

    验证码简介 验证码的作用: 验证码在现在来说,是很常见的东西,可以一定程度的保护网站,比如防止网络爬虫恶意爬取网站数据啊,减少低级的攻击啊什么的.但是高级点的骚操作还是不太好防范,所以现在的验证码平台 ...

  6. c/c++ 多线程 mutex的理解

    多线程 mutex的理解 mutex,我的理解是每个mutex对象都是一个带锁头的门,这个门有两个状态,门开着和门关着,感觉像是废话... 当想查看门的里东西,或者把东西放进门里,或者从门里拿出东西前 ...

  7. c/c++ 网络编程 getaddrinfo 函数

    网络编程 getaddrinfo 函数 解析网址,返回IP地址. 例子: #include <iostream> #include <string.h> #include &l ...

  8. iOS 12.1 跳转页面时 tabBar闪动

    最新iOS 12.1系统,self.hidesBottomBarWhenPushed = YES,tabBar发生闪动 设置为不透明就行了.[[UITabBar appearance] setTran ...

  9. git 命令添加整个文件夹以及文件夹下的内容

    对于一个文件夹提交到服务器上,喜欢用 git add .(后面为".") 这种情况对于一个文件夹的还是很有用的,但出现了多个不同文件夹后,要分别提交就不能这么用了, 可以使用如下指 ...

  10. 好程序员web前端分享值得参考的css理论:OOCSS、SMACSS与BEM

    好程序员web前端分享值得参考的css理论:OOCSS.SMACSS与BEM 最近在The Sass Way里看到了Modular CSS typography一文,发现文章在开头部分就提到了OOCS ...