前言

在项目中我们会经常遇到对象的映射,比如像Model和Dto之间的映射,或者是对象的深拷贝,这些都是需要我们自己实现的。此时,项目中会出现很多初始化对象的代码,这些代码写起来相当的枯燥乏味,那么有没有什么办法减轻我们的工作量,使得我们可以把时间花费到业务功能上呢?

目前,.Net中的对象映射框架,功能强大且性能极佳的对象映射框架已经存在,其中使用最多的有:

说到对象映射框架,大家想到的最多的是AutoMapper,可能很多人连Mapster都没听过,但不可否认的是Mapster确实是一个很好的对象映射框架,但由于中文文档的缺失,导致在国内知名度不是很高,今天我们就来介绍一下Mapster提供了哪些功能,如何在项目中使用它,Masa提供的Mapster又做了什么?

Mapster 简介

Mapster是一个使用简单,功能强大的对象映射框架,自2014年开源到现在已经过去8个年头,截止到现在,github上已经拥有2.6k的star,并保持着每年3次的发版频率,其功能与AutoMapper类似,提供对象到对象的映射、并支持IQueryable到对象的映射,与AutoMapper相比,在速度和内存占用方面表现的更加优秀,可以在只使用1/3内存的情况下获得4倍的性能提升,那我们下面就来看看Mapster如何使用?

准备工作

  • 新建一个控制台项目Assignment.Mapster,并安装Mapster

    dotnet add package Mapster --version 7.3.0

映射到新对象

  1. 新建类UserDto

    public class UserDto
    {
    public int Id { get; set; } public string Name { get; set; } public uint Gender { get; set; } public DateTime BirthDay { get; set; }
    }
  2. 新建一个匿名对象,作为待转换的对象源

    var user = new
    {
    Id = 1,
    Name = "Tom",
    Gender = 1,
    BirthDay = DateTime.Parse("2002-01-01")
    };
  3. 将user源对象映射到为目标对象 (UserDto)

    var userDto = user.Adapt<UserDto>();
    Console.WriteLine($"映射到新对象,Name: {userDto.Name}");

运行控制台程序验证转换成功:

数据类型

除了提供对象到对象的映射,还支持数据类型的转换,如:

基本类型

  • 提供类型映射的功能,类似Convert.ChangeType()

    string res = "123";
    decimal i = res.Adapt<decimal>(); //equal to (decimal)123;
    Console.WriteLine($"结果为:{i == int.Parse(res)}");

运行控制台程序:

枚举类型

  • 把枚举映射到数字类型,同样也支持字符串到枚举和枚举到字符串的映射,比.NET的默认实现快两倍

    var fileMode = "Create, Open".Adapt<FileMode>();//等于 FileMode.Create | FileMode.Open
    Console.WriteLine($"枚举类型转换的结果为:{fileMode == (FileMode.Create | FileMode.Open)}");

运行控制台程序验证转换成功:

Queryable扩展

Mapster提供了Queryable的扩展,用于实现DbContext的按需查找,例如:

  1. 新建类UserDbContext

    using Assignment.Mapster.Domain;
    using Microsoft.EntityFrameworkCore; namespace Assignment.Mapster.Infrastructure; public class UserDbContext : DbContext
    {
    public DbSet<User> User { get; set; } protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
    var dataBaseName = Guid.NewGuid().ToString();
    optionsBuilder.UseInMemoryDatabase(dataBaseName);//使用内存数据库,方便测试
    }
    }
  2. 新建类User

    public class User
    {
    public int Id { get; set; } public string Name { get; set; } public uint Gender { get; set; } public DateTime BirthDay { get; set; } public DateTime CreationTime { get; set; } public User()
    {
    CreationTime = DateTime.Now;
    }
    }
  3. 使用基于Queryable的扩展方法ProjectToType

    using (var dbContext = new UserDbContext())
    {
    dbContext.Database.EnsureCreated(); dbContext.User.Add(new User()
    {
    Id = 1,
    Name = "Tom",
    Gender = 1,
    BirthDay = DateTime.Parse("2002-01-01")
    });
    dbContext.SaveChanges(); var userItemList = dbContext.User.ProjectToType<UserDto>().ToList();
    }

运行控制台程序验证转换成功:

除此之外,Mapster还提供了映射前/后处理,拷贝与合并以及映射配置嵌套支持,详细可查看文档,既然Mapster已经如此强大,那我直接使用它就可以了,为什么还要使用Masa提供的Mapper呢?

什么是Masa.Contrib.Data.Mapping.Mapster?

Masa.Contrib.Data.Mapping.Mapster是基于Mapster的一个对象到对象的映射器,并在原来Mapster的基础上增加自动获取并使用最佳构造函数映射,支持嵌套映射,减轻映射的工作量。

映射规则

  • 目标对象没有构造函数时:使用空构造函数,映射到字段和属性。

  • 目标对象存在多个构造函数:获取最佳构造函数映射

    最佳构造函数: 目标对象构造函数参数数量从大到小降序查找,参数名称一致(不区分大小写)且参数类型与源对象属性一致

准备工作

  • 新建一个控制台项目Assignment.Masa.Mapster,并安装Masa.Contrib.Data.Mapping.MapsterMicrosoft.Extensions.DependencyInjection

    dotnet add package Masa.Contrib.Data.Mapping.Mapster --version 0.4.0-rc.4
    dotnet add package Microsoft.Extensions.DependencyInjection --version 6.0.0
  1. 新建类OrderItem

    public class OrderItem
    {
    public string Name { get; set; } public decimal Price { get; set; } public int Number { get; set; } public OrderItem(string name, decimal price) : this(name, price, 1)
    { } public OrderItem(string name, decimal price, int number)
    {
    Name = name;
    Price = price;
    Number = number;
    }
    }
  2. 新建类Order

    public class Order
    {
    public string Name { get; set; } public decimal TotalPrice { get; set; } public List<OrderItem> OrderItems { get; set; } public Order(string name)
    {
    Name = name;
    } public Order(string name, OrderItem orderItem) : this(name)
    {
    OrderItems = new List<OrderItem> { orderItem };
    TotalPrice = OrderItems.Sum(item => item.Price * item.Number);
    }
    }
  3. 修改类Program

    using Assignment.Masa.Mapster.Domain.Aggregate;
    using Masa.BuildingBlocks.Data.Mapping;
    using Masa.Contrib.Data.Mapping.Mapster;
    using Microsoft.Extensions.DependencyInjection; Console.WriteLine("Hello Masa Mapster!"); IServiceCollection services = new ServiceCollection();
    services.AddMapping(); var request = new
    {
    Name = "Teach you to learn Dapr ……",
    OrderItem = new OrderItem("Teach you to learn Dapr hand by hand", 49.9m)
    };
    var serviceProvider = services.BuildServiceProvider();
    var mapper = serviceProvider.GetRequiredService<IMapper>();
    var order = mapper.Map<Order>(request); Console.WriteLine($"{nameof(Order.TotalPrice)} is {order.TotalPrice}");//控制台输出49.9 Console.ReadKey();

如果转换成功,TotalPrice的值应该是49.9,那么我们运行控制台程序来验证转换是否成功:

如何实现

上面我们提到了Masa.Contrib.Data.Mapping.Mapster可以自动获取并使用最佳构造函数映射,进而完成对象到对象的映射,那么它是如何实现的呢?会不会对性能有什么影响呢?

做到自动获取并使用最佳构造函数映射是使用的Mapster提供的构造函数映射的功能,通过指定构造函数,完成对象到对象的映射。

查看文档

总结

目前Masa.Contrib.Data.Mapping.Mapster的功能相对较弱,当前版本与Mapster的相比仅仅增加了一个自动获取并使用最佳构造函数的功能,让我们在面对无空构造函数且拥有多个构造函数的类时也能轻松的完成映射,不需要额外多写一行代码。

但我觉得Masa版的Mapping最大的好处是项目依赖的是BuildingBlocks下的IMapper,而不是Mapster,这也就使得我们的项目与具体的映射器实现脱离,如果我们被要求项目必须要使用AutoMapper,只需要实现AutoMapper版的IMapper即可,无需更改太多的业务代码,仅需要更换一下引用的包即可,这也是BuildingBlocks的魅力所在

本章源码

Assignment04

https://github.com/zhenlei520/MasaFramework.Practice

开源地址

MASA.BuildingBlocks:https://github.com/masastack/MASA.BuildingBlocks

MASA.Contrib:https://github.com/masastack/MASA.Contrib

MASA.Utils:https://github.com/masastack/MASA.Utils

MASA.EShop:https://github.com/masalabs/MASA.EShop

MASA.Blazor:https://github.com/BlazorComponent/MASA.Blazor

如果你对我们的 MASA Framework 感兴趣,无论是代码贡献、使用、提 Issue,欢迎联系我们

对象映射 - Mapping.Mapster的更多相关文章

  1. [非专业翻译] 高性能对象映射框架 - Mapster

    [非专业翻译] 高性能对象映射框架 - Mapster 系列介绍 [非专业翻译] 是对没有中文文档进行翻译的系列博客,文章由机翻和译者自己理解构成,和原文相比有所有不通,但意思基本一致. 因个人能力有 ...

  2. 一:ORM关系对象映射(Object Relational Mapping,简称ORM)

    狼来的日子里! 奋发博取 10)django-ORM(创建,字段类型,字段参数) 一:ORM关系对象映射(Object Relational Mapping,简称ORM) ORM分两种: DB fir ...

  3. 基于JsonPath和XmlPath的对象映射(Object Mapping)

    rest-assured支持映射Java对象到Json和XML以及从Json和XML中映射到Java对象.Json映射需要在classpath 中有Jackson.Jackson 2或者是Gson,X ...

  4. 【5min+】 对象映射只有AutoMapper?试试Mapster

    系列介绍 [五分钟的dotnet]是一个利用您的碎片化时间来学习和丰富.net知识的博文系列.它所包含了.net体系中可能会涉及到的方方面面,比如C#的小细节,AspnetCore,微服务中的.net ...

  5. KnockoutJS 3.X API 第八章 映射(mapping)插件

    Knockout旨在允许您将任意JavaScript对象用作视图模型. 只要一些视图模型的属性是observables,您可以使用KO将它们绑定到您的UI,并且UI将在可观察属性更改时自动更新. 大多 ...

  6. php设计模式 数据对象映射模式

    数据对象映射模式,是将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作. 在代码中实现数据对象映射模式,实现一个ORM类,将复杂的sql语句映射成对象属性的操作.对象关系映射(Obje ...

  7. PHP 设计模式 笔记与总结(9)数据对象映射模式

    [数据对象映射模式] 是将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作.例如在代码中 new 一个对象,使用数据对象映射模式就可以将对象的一些操作比如设置一些属性,就会自动保存到数 ...

  8. .NET平台开源项目速览-最快的对象映射组件Tiny Mapper之项目实践

    心情小札:近期换了工作,苦逼于22:00后下班,房间一篇狼藉~ 小翠鄙视到:"你就适合生活在垃圾堆中!!!" 晚上浏览博客园 看到一篇非常实用的博客:.NET平台开源项目速览(14 ...

  9. 关于iOS上的对象映射公用方法-备

    具体的使用方法,请见下面说明,或者见工程里的单元测试代码.或者,参考原始文档: https://github.com/mystcolor/JTObjectMapping 使用方法 ======== 绝 ...

随机推荐

  1. .NET MAUI RC 是完整的 API 并准备好起飞 (GA)

    2022年4月12日 微软发布了 .NET Multiplatform App UI (.NET MAUI) 作为候选版本RC ,具体参见 https://devblogs.microsoft.com ...

  2. 2021.07.20 P3951 小凯的疑惑(最大公因数,未证)

    2021.07.20 P3951 小凯的疑惑(最大公因数,未证) 重点: 1.最大公因数 题意: 求ax+by最大的表示不了的数(a,b给定 x,y非负). 分析: 不会.--2021.07.20 代 ...

  3. Java 字符串Split方法的一个坑

    java字符串的split,只传一个参数,后面空白的字符串会被忽略: public static void main(String[] args) { String str = "ab|c| ...

  4. Vue.js Mixins 混入使用

    Mixins一般有两种用途: 1.在你已经写好了构造器后,需要增加方法或者临时的活动时使用的方法,这时用混入会减少源代码的污染. 2.很多地方都会用到的公用方法,用混入的方法可以减少代码量,实现代码重 ...

  5. Java基础语法Day_02-03(数据类型、运算符、方法、循环结构)

    第5节 数据类型转换 day02_01_数据类型转换_自动转换 day02_02_数据类型转换_强制转换 day02_03_数据类型转换_注意事项 day02_04_ASCII编码表 第6节 运算符 ...

  6. 基础知识:CERT内部威胁定义以及四大原因

    我们从CERT的内部威胁定义中,可以分析.提取出内部威胁的关键特征,而这些特征也是内部威胁与外部威胁区别的最主要因素.通常来说,内部威胁具有以下特征: 1.透明性:攻击者来自安全边界内部,因此攻击者可 ...

  7. 【CSAPP】Architecture Lab 实验笔记

    archlab属于第四章的内容.这章讲了处理器体系结构,就CPU是怎样构成的.看到时候跃跃欲试,以为最后实验是真要去造个CPU,配套资料也是一如既往的豪华,合计四十多页的参考手册,一大包的源码和测试程 ...

  8. 详谈:pNFS增强文件系统架构

    点击上方"开源Linux",选择"设为星标" 回复"学习"获取独家整理的学习资料! 通过 NFS(由服务器.客户机软件和两者之间的协议组成) ...

  9. 使用DSVPN解决分支网络出口为ADSL场景下的内网互通

    背景 最近接到一个项目是一家机构总部与多个分支之间的内网互通,总部具有固定ip,分部是使用adsl动态获取的不固定公网ip,由于两端互联网ip不固定所以不能使用传统的GRE技术来实现,所以最后经过评估 ...

  10. Java中的线程到底有哪些安全策略

    摘要:Java中的线程到底有哪些安全策略呢?本文就为你彻底分析下! 本文分享自华为云社区<[高并发]线程安全策略>,作者:冰 河 . 一.不可变对象 不可变对象需要满足的条件 (1)对象创 ...