前のページ
プロジェクトでは、ModelとDtoの間のマッピングや、オブジェクトの深いコピーなど、オブジェクトのマッピングに遭遇しますが、これらはすべて自分で実装する必要があります。この時点で、プロジェクトにはオブジェクトを初期化するコードがたくさんありますが、これらのコードはかなり退屈です。作業負荷を軽減し、ビジネス機能に時間を費やすことができるようにする方法はありませんか?
現在、. Netのオブジェクトマッピングフレームワークには強力で高性能なオブジェクトマッピングフレームワークが存在し、その中で最も使用されているのは. 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
###新しいオブジェクトへのマッピング
- 新建类
UserDto
public class UserDto
{
public int Id { get; set; }
public string Name { get; set; }
public uint Gender { get; set; }
public DateTime BirthDay { get; set; }
}
- 変換するオブジェクトのソースとして匿名オブジェクトを作成します。
var user = new
{
Id = 1,
Name = "Tom",
Gender = 1,
BirthDay = DateTime.Parse("2002-01-01")
};
- 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のデフォルト実装よりも2倍高速です。
var fileMode = "Create, Open".Adapt<FileMode>();//等于 FileMode.Create | FileMode.Open
Console.WriteLine($"枚举类型转换的结果为:{fileMode == (FileMode.Create | FileMode.Open)}");
コンソール·プログラムを実行して、変換が成功したことを確認

クエリ拡張機能
Mapsterは、DbContextのオンデマンドルックアップを実装するためのQueryable拡張機能を提供します。
- 新建类
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);//使用内存数据库,方便测试
}
}
- 新建类
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;
}
}
- 使用基于 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.Mapster,Microsoft.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
- 新建类
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;
}
}
- 新建类
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);
}
}
- 修改类
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フレームワークに興味がある場合は、お問い合わせください。
