【.NET】Mapster

2023-12-24 13:12
文章标签 net mapster

本文主要是介绍【.NET】Mapster,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

  • 概述
  • 具体
    • 安装 Mapster
    • 定义实体
    • 简单使用
    • Mapster 配置 (TypeAdapterConfig)
      • 方式一
      • 方式二
    • 忽略字段
    • 分支(Fork)
    • NewConfig 方法
    • 运行时传参
    • 其他
    • 小技巧
      • Adapt 扩展方法的使用
      • 拦截映射前后
  • 来源

概述

Mapster是一个高性能的用于对象映射的类库,同类型的产品还有AutoMapper。它提供了一系列的API和工具,以下为几个重要的类和接口:

  • @Adapt注解:用于将实体类映射到数据库表中的指定列上。
  • @Mapper注解:用于将实体类映射到数据库表中的指定列上。
  • Entity接口:定义了实体类的属性和映射规则。
  • Mapper接口:定义了映射规则的具体实现。
  • Query接口:定义了查询语句的规则。
  • DataStore接口:定义了数据存储的接口。

Mapster与AutoMapper的性能对比:

方法平均值标准偏差错误第0代第1代第2代分配
“Mapster 6.0.0”108.59毫秒1.198毫秒1.811毫秒31000--124.36 MB
“Mapster 6.0.0(罗斯林)”38.45毫秒0.494毫秒0.830毫秒31142.8571--124.36 MB
'Mapster 6.0.0(FEC)'37.03毫秒0.281毫秒0.472毫秒29642.8571--118.26 MB
'Mapster 6.0.0(Codegen)'34.16毫秒0.209毫秒0.316毫秒31133.3333--124.36 MB
“ExpressMapper 1.9.1”205.78毫秒5.357毫秒8.098毫秒59000--236.51 MB
“AutoMapper 10.0.0”420.97毫秒23.266毫秒35.174毫秒87000--350.95 MB

具体

安装 Mapster

PM> Install-Package Mapster或者 dotnet add package Mapster

定义实体

目的:使用 Mapster 实现 User 到 UserDto 的映射

public class User
{public string Name { get; set; }public int Age { get; set; }public string Sex { get; set; }public string like { get; set; }
}public class UserDto
{public string name { get; set; }public int UserAge { get; set; }public string UserSex { get; set; }public string like { get; set; }
}

简单使用

/*
* 默认情况下,无需任何配置,Mapster会根据两个实体字段名称相同进行匹配
* 第一次调用时,配置会被缓存,第二次将会从缓存中取,以此提升性能
*/
var user = new User();
var dto = user.Adapt<UserDto>();//映射为新对象
user.Adapt(dto);//在目标对象的基础上进行映射//注意:Adapt扩展方法使用的配置为 `TypeAdapterConfig.GlobalSettings`

Mapster 配置 (TypeAdapterConfig)

可以直接使用 Mapster 内置的全局静态配置 TypeAdapterConfig.GlobalSettings,也可以实例化一个配置 new TypeAdapterConfig()推荐使用实例化的方式,对 TypeAdapterConfig 进行映射配置。

注:Mapster 默认匹配规则是相同字段名之间进行映射。

方式一

直接在 TypeAdapterConfig 配置对象的映射关系

var config = new TypeAdapterConfig();
//映射规则
config.ForType<User, UserDto>().Map(dest => dest.UserAge, src => src.Age).Map(dest => dest.UserSex, src => src.Sex);var mapper = new Mapper(config);//务必将mapper设为单实例var user = new User{Name = "xiaowang",Age = 18,Sex = "boy"};
var dto = mapper.Map<UserDto>(user);

字段带有前后缀,可以使用 NameMatchingStrategy.ConvertDestinationMemberName对目标字段名称进行替换,使得它和源字段名称相同。还有替换源字段的方法NameMatchingStrategy.ConvertSourceMemberName

注意:如果一个ForType定义多个NameMatchingStrategy,后定义的会覆盖先定义的规则,所以只有最后定义的规则会生效

var config = new TypeAdapterConfig();
//使用
config.ForType<User, UserDto>().NameMatchingStrategy(NameMatchingStrategy.ConvertDestinationMemberName(dest => dest.Replace("User", "")));

方式二

使用接口的方式,需要实现 IRegister

//实现接口 IRegister
public class UserDtoRegister : IRegister
{public void Register(TypeAdapterConfig config){config.ForType<User,UserDto>()Map(dest => dest.UserAge, src => src.Age);//...}
}//实例化Mapper
var config = new TypeAdapterConfig();
//var config = TypeAdapterConfig.GlobalSettings;
//只有要给定 IRegister 所在的程序集名称,Mapster 会自动识别 IRegister,进行配置注入。
config.Scan("程序集名称1","程序集名称2");
var mapper = new Mapper(config);//务必设置为单实例

忽略字段

var config = new TypeAdapterConfig();
//映射规则
config.ForType<User, UserDto>().Map(dest => dest.UserAge, src => src.Age).Map(dest => dest.UserSex, src => src.Sex);.IgnoreNullValues(true)//忽略空值映射.Ignore(dest => dest.UserAge)//忽略指定字段.IgnoreAttribute(typeof(DataMemberAttribute))//忽略指定特性的字段.NameMatchingStrategy(NameMatchingStrategy.IgnoreCase)//忽略字段名称的大小写.IgnoreNonMapped(true);//忽略除以上配置的所有字段config.ForType<User,UserDto>().IgnoreMember((member, side) => !member.Type.Namespace.StartsWith("System"));//实现更细致的忽略规则

member和side分别对应IMemberModel和MemberSide,这里我贴出相应的源码。

//包含了映射类型的信息
public interface IMemberModel
{Type Type { get; }string Name { get; }object? Info { get; }AccessModifier SetterModifier { get; }AccessModifier AccessModifier { get; }IEnumerable<object> GetCustomAttributes(bool inherit);
}
//标识当前是源类型还是目标类型
public enum MemberSide
{Source = 0,Destination = 1
}

分支(Fork)

Mapster 的 Fork 功能允许我们定义局部的映射规则,并且分支不会重复编译,不需要考虑性能问题。

var config = new TypeAdapterConfig();
var mapper = new Mapper(config);var user = new User{Name = "xiaowang",Age = 18,Sex = "boy"};var dto = mapper.From(user).ForkConfig(forked =>{//该分支规则,不会重复编译,仅限该语句中有效,不会影响config的配置forked.ForType<User, UserDto>().Map(dest => dest.name, src => src.Name);}).AdaptToType<UserDto>();//映射为新对象dto = mapper.From(user).ForkConfig(forked =>{forked.ForType<User, UserDto>().Map(dest => dest.name, src => src.Name);}).AdaptTo(new UserDto());//在目标对象基础上进行映射

NewConfig 方法

NewConfig 方法允许我们对两个类型之间新建配置,如果两个类型之前配置了映射关系,则 NewConfig 方法会覆盖之前的配置

var config = new TypeAdapterConfig();
config.ForType<User,UserDto>().Map(dest => dest.UserAge, src => src.Age);
//...//覆盖 User 和 UserDto 之前的配置
config.NewConfig<User,UserDto>().Map(dest=>dest.UserAge,src=>100);//扩展知识:覆盖Mapster默认静态配置
TypeAdapterConfig<User,UserDto>.NewConfig().Default.NameMatchingStrategy(NameMatchingStrategy.IgnoreCase);

运行时传参

允许运行时传入数据,干预映射过程

var config = new TypeAdapterConfig();
config.ForType<User, UserDto>().Map(dest => dest.name, src => MapContext.Current.Parameters["userName"]);//配置运行时参数
var mapper = new Mapper(config);//使用时传入数据
var user = new User();
var dto = mapper.From(user).BuildAdapter().AddParameters("userName","xiaowang").AdaptToType<UserDto>();

其他

我们尽量不要把实体间的映射规则配置到 TypeAdapterConfig.GlobalSettings (默认配置)。随着业务的发展,一个配置很难兼顾所有业务,可能会出行冲突的情况,相对复杂的业务,可以新建一个TypeAdapterConfig,或者使用 config.Clone()能轻松复制一份配置。全局配置可以放一些简单的配置项,例如:映射时忽略大小写。

注意:Adapt 扩展方法使用的是 TypeAdapterConfig.GlobalSettings

小技巧

Adapt 扩展方法的使用

Dictionary<string,object> dict = new User().Adapt<Dictionary<string,object>>();//object 到 Dictionary 的转换
string s = 123.Adapt<string>(); //equal to 123.ToString();int i = "123".Adapt<int>();  //equal to int.Parse("123");

拦截映射前后

BeforeMapping方法和 AfterMapping

//BeforeMapping 映射执行前
config.ForType<User, UserDto>().BeforeMapping((src, dest) =>{src.Age = 100;dest.UserAge = src.Age + 10;});//AfterMapping 映射执行后
//...

来源

C# Mapster 对象映射器学习
C#-对象映射器(二)-Mapster帮助类

这篇关于【.NET】Mapster的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/531895

相关文章

解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题

《解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘问题》:本文主要介绍解决未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4... 目录未解析的依赖项:‘net.sf.json-lib:json-lib:jar:2.4‘打开pom.XM

javax.net.ssl.SSLHandshakeException:异常原因及解决方案

《javax.net.ssl.SSLHandshakeException:异常原因及解决方案》javax.net.ssl.SSLHandshakeException是一个SSL握手异常,通常在建立SS... 目录报错原因在程序中绕过服务器的安全验证注意点最后多说一句报错原因一般出现这种问题是因为目标服务器

使用easy connect之后,maven无法使用,原来需要配置-Djava.net.preferIPv4Stack=true问题

《使用easyconnect之后,maven无法使用,原来需要配置-Djava.net.preferIPv4Stack=true问题》:本文主要介绍使用easyconnect之后,maven无法... 目录使用easGWowCy connect之后,maven无法使用,原来需要配置-DJava.net.pr

在.NET平台使用C#为PDF添加各种类型的表单域的方法

《在.NET平台使用C#为PDF添加各种类型的表单域的方法》在日常办公系统开发中,涉及PDF处理相关的开发时,生成可填写的PDF表单是一种常见需求,与静态PDF不同,带有**表单域的文档支持用户直接在... 目录引言使用 PdfTextBoxField 添加文本输入域使用 PdfComboBoxField

基于.NET编写工具类解决JSON乱码问题

《基于.NET编写工具类解决JSON乱码问题》在开发过程中,我们经常会遇到JSON数据处理的问题,尤其是在数据传输和解析过程中,很容易出现编码错误导致的乱码问题,下面我们就来编写一个.NET工具类来解... 目录问题背景核心原理工具类实现使用示例总结在开发过程中,我们经常会遇到jsON数据处理的问题,尤其是

Node.js net模块的使用示例

《Node.jsnet模块的使用示例》本文主要介绍了Node.jsnet模块的使用示例,net模块支持TCP通信,处理TCP连接和数据传输,具有一定的参考价值,感兴趣的可以了解一下... 目录简介引入 net 模块核心概念TCP (传输控制协议)Socket服务器TCP 服务器创建基本服务器服务器配置选项服

.NET利用C#字节流动态操作Excel文件

《.NET利用C#字节流动态操作Excel文件》在.NET开发中,通过字节流动态操作Excel文件提供了一种高效且灵活的方式处理数据,本文将演示如何在.NET平台使用C#通过字节流创建,读取,编辑及保... 目录用C#创建并保存Excel工作簿为字节流用C#通过字节流直接读取Excel文件数据用C#通过字节

poj 1258 Agri-Net(最小生成树模板代码)

感觉用这题来当模板更适合。 题意就是给你邻接矩阵求最小生成树啦。~ prim代码:效率很高。172k...0ms。 #include<stdio.h>#include<algorithm>using namespace std;const int MaxN = 101;const int INF = 0x3f3f3f3f;int g[MaxN][MaxN];int n

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

2、PF-Net点云补全

2、PF-Net 点云补全 PF-Net论文链接:PF-Net PF-Net (Point Fractal Network for 3D Point Cloud Completion)是一种专门为三维点云补全设计的深度学习模型。点云补全实际上和图片补全是一个逻辑,都是采用GAN模型的思想来进行补全,在图片补全中,将部分像素点删除并且标记,然后卷积特征提取预测、判别器判别,来训练模型,生成的像