前言
在項目中我們會經(jīng)常遇到對象的映射,比如像Model和Dto之間的映射,或者是對象的深拷貝,這些都是需要我們自己實現(xiàn)的。此時,項目中會出現(xiàn)很多初始化對象的代碼,這些代碼寫起來相當?shù)目菰锓ξ?,那么有沒有什么辦法減輕我們的工作量,使得我們可以把時間花費到業(yè)務功能上呢?
目前,.Net中的對象映射框架,功能強大且性能極佳的對象映射框架已經(jīng)存在,其中使用最多的有:
- Mapster
- AutoMapper
說到對象映射框架,大家想到的最多的是AutoMapper
,可能很多人連Mapster
都沒聽過,但不可否認的是Mapster
確實是一個很好的對象映射框架,但由于中文文檔的缺失,導致在國內(nèi)知名度不是很高,今天我們就來介紹一下Mapster
提供了哪些功能,如何在項目中使用它,Masa
提供的Mapster
又做了什么?
Mapster 簡介
Mapster
是一個使用簡單,功能強大的對象映射框架,自2014年開源到現(xiàn)在已經(jīng)過去8個年頭,截止到現(xiàn)在,github上已經(jīng)擁有2.6k的star,并保持著每年3次的發(fā)版頻率,其功能與AutoMapper類似,提供對象到對象的映射、并支持IQueryable到對象的映射,與AutoMapper
相比,在速度和內(nèi)存占用方面表現(xiàn)的更加優(yōu)秀,可以在只使用1/3內(nèi)存的情況下獲得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; } }
-
新建一個匿名對象,作為待轉(zhuǎn)換的對象源
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}");
運行控制臺程序驗證轉(zhuǎn)換成功:
數(shù)據(jù)類型
除了提供對象到對象的映射,還支持數(shù)據(jù)類型的轉(zhuǎn)換,如:
基本類型
-
提供類型映射的功能,類似Convert.ChangeType()
string res = "123"; decimal i = res.Adapt<decimal>(); //equal to (decimal)123; Console.WriteLine($"結(jié)果為:{i == int.Parse(res)}");
運行控制臺程序:
枚舉類型
-
把枚舉映射到數(shù)字類型,同樣也支持字符串到枚舉和枚舉到字符串的映射,比.NET的默認實現(xiàn)快兩倍
var fileMode = "Create, Open".Adapt<FileMode>();//等于 FileMode.Create | FileMode.Open Console.WriteLine($"枚舉類型轉(zhuǎn)換的結(jié)果為:{fileMode == (FileMode.Create | FileMode.Open)}");
運行控制臺程序驗證轉(zhuǎn)換成功:
Queryable擴展
Mapster提供了Queryable的擴展,用于實現(xiàn)DbContext的按需查找,例如:
-
新建類
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);//使用內(nèi)存數(shù)據(jù)庫,方便測試 } }
-
新建類
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(); }
運行控制臺程序驗證轉(zhuǎn)換成功:
除此之外,Mapster
還提供了映射前/后處理,拷貝與合并以及映射配置嵌套支持,詳細可查看文檔,既然Mapster
已經(jīng)如此強大,那我直接使用它就可以了,為什么還要使用Masa
提供的Mapper呢?
什么是Masa.Contrib.Data.Mapping.Mapster?
Masa.Contrib.Data.Mapping.Mapster
是基于Mapster
的一個對象到對象的映射器,并在原來Mapster
的基礎上增加自動獲取并使用最佳構(gòu)造函數(shù)映射,支持嵌套映射,減輕映射的工作量。
映射規(guī)則
-
目標對象沒有構(gòu)造函數(shù)時:使用空構(gòu)造函數(shù),映射到字段和屬性。
-
目標對象存在多個構(gòu)造函數(shù):獲取最佳構(gòu)造函數(shù)映射
最佳構(gòu)造函數(shù): 目標對象構(gòu)造函數(shù)參數(shù)數(shù)量從大到小降序查找,參數(shù)名稱一致(不區(qū)分大小寫)且參數(shù)類型與源對象屬性一致
準備工作
-
新建一個控制臺項目
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();
如果轉(zhuǎn)換成功,TotalPrice的值應該是49.9,那么我們運行控制臺程序來驗證轉(zhuǎn)換是否成功:
如何實現(xiàn)
上面我們提到了Masa.Contrib.Data.Mapping.Mapster
可以自動獲取并使用最佳構(gòu)造函數(shù)映射,進而完成對象到對象的映射,那么它是如何實現(xiàn)的呢?會不會對性能有什么影響呢?
做到自動獲取并使用最佳構(gòu)造函數(shù)映射是使用的Mapster
提供的構(gòu)造函數(shù)映射的功能,通過指定構(gòu)造函數(shù),完成對象到對象的映射。
查看文檔
總結(jié)
目前Masa.Contrib.Data.Mapping.Mapster
的功能相對較弱,當前版本與Mapster
的相比僅僅增加了一個自動獲取并使用最佳構(gòu)造函數(shù)的功能,讓我們在面對無空構(gòu)造函數(shù)且擁有多個構(gòu)造函數(shù)的類時也能輕松的完成映射,不需要額外多寫一行代碼。
但我覺得Masa
版的Mapping最大的好處是項目依賴的是BuildingBlocks
下的IMapper
,而不是Mapster
,這也就使得我們的項目與具體的映射器實現(xiàn)脫離,如果我們被要求項目必須要使用AutoMapper
,只需要實現(xiàn)AutoMapper
版的IMapper
即可,無需更改太多的業(yè)務代碼,僅需要更換一下引用的包即可,這也是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文章來源:http://www.zghlxwxcb.cn/news/detail-442496.html
如果你對我們的 MASA Framework 感興趣,無論是代碼貢獻、使用、提 Issue,歡迎聯(lián)系我們文章來源地址http://www.zghlxwxcb.cn/news/detail-442496.html
到了這里,關(guān)于4. 對象映射 - Mapping.Mapster的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!