八、对象映射指南 将一个对象的值批量映射到另一个对象中,支持自定义映射规则。
传统模式(不推荐)
假设有两个类型:Student
和 StudentDto
,现在需要将 Student
对象赋值给 StudentDto
Student
复制 public class Student
{
public string FirstName { get ; set ; }
public string LastName { get ; set ; }
public int Age { get ; set ; }
public string Address { get ; set ; }
public string Gender { get ; set ; }
}
StudentDto
复制 public class StudentDto
{
public string FullName { get ; set ; }
public int Age { get ; set ; }
public string Gender { get ; set ; }
}
传统赋值模式代码如下:
复制 var student = new Student ()
{
FirstName = "Monk" ,
LastName = "Soul" ,
Age = 27 ,
Address = "广东省珠海市香洲区吉大路" ,
Gender = "男"
};
// 赋值
var studentDto = new StudentDto ()
{
FullName = student . FirstName + student . LastName ,
Age = student . Age ,
Gender = student . Gender
}
通过上面的代码,可能一部分读者觉的这是一件很正常的代码,没有什么不妥。
确实,这样的代码咋看没什么不妥,但是有几个漏洞 :
如果多次需要将 Student映射到 StudentDto中,则这样的代码散落在很大地方,给维护带来了极大的困扰
这样的赋值操作实际上污染了业务逻辑代码,不利于后续的统一管理
这样的赋值操作实在是多,无意增加了项目包的大小,开发效率也会低下
所以,我们迫切需要一种更加灵活、简易的对象赋值(映射)方式。
对象映射组件(推荐)
正是由于传统组件带来的漏洞及效率低下问题,所以就有第三方开发者提供了解决方案,在众多的解决方案中,无外乎 AutoMapper 和 Mapster 最为出色。
由于 Mapster 简单易用,而且性能极高,所以 Hoa Framework 将 Mapster 作为默认的映射组件。
Mapster 使用
简单使用
将源对象映射到目标对象,并创建新的目标对象
复制 var destObject = sourceObject . Adapt < Destination >();
将源对隐射到已存在的目标对象
复制 var destObject = new DestObject (){ .. .};
sourceObject . Adapt (destObject );
自定义映射规则
通常,我们的属性并非总是一一对应映射,我们可能会进行一些操作或重写,比如:StudentDto.FullName
由 Student.FirstName
+ Student.LastName
组成。
自定义映射支持多种方式,在 Hoa Framework 中,建议程序员将 自定义映射规则配置在 Hoa.Application.ManualMapper.cs
中,方便集中管理。
复制 using Mapster ;
namespace Hoa . Application
{
public class ManualMapper : IRegister
{
public void Register ( TypeAdapterConfig config)
{
config . ForType < SourceObject , DestinationObject >()
. Map (dest => dest . FullName ,
src => string . Format ( "{0} {1}" , src . FirstName , src . LastName ));
config . ForType < DestinationObject , SourceObject >()
. Map (dest => dest . Gender ,
src => src . GenderString );
config . ForType < SourceObject , DestinationObject >()
. Map (dest => dest . FullName , src => "Sig. " + src . FullName , srcCond => srcCond . Country == "Italy" )
. Map (dest => dest . FullName , src => "Sr. " + src . FullName , srcCond => srcCond . Country == "Spain" )
. Map (dest => dest . FullName , src => "Mr. " + src . FullName );
}
}
}
更多自定义映射规则可查看官方文档 。
特殊映射
Hoa Framework 内置了将类似 GROUP_ID
->GroupId
和GroupId
->GROUP_ID
两种映射方式,这是 Mapster 默认不具备的功能。
配置Hoa.Application.ManualMapper.cs
如下:
复制 using Mapster ;
using System . Text ;
namespace Hoa . Application . Authorization . Dtos
{
public class Mapper : IRegister
{
public void Register ( TypeAdapterConfig config)
{
config . ForType < SignInInput , SignInInput2 >()
. ConvertSourceMemberUnderlineSplitNameToCamelCase (); // 支持:GROUP_ID -> GroupId 方式
config . ForType < SignInInput2 , SignInInput >()
. ConvertSourceMemberCamelCaseNameToUnderlineSplit (); // 支持:GroupId -> GROUP_ID 方式
}
}
}
数据库实体映射说明
将 EF Core 查询的结果集映射到 Dto 中。
复制 using ( MyDbContext context = new MyDbContext ())
{
// 不使用 Mapster 时候
var destinations = context . Sources . Select (c => new Destination {
Id = p . Id ,
Name = p . Name ,
Surname = p . Surname ,
....
})
. ToList ();
}
复制 using ( MyDbContext context = new MyDbContext ())
{
// 使用 Mapster 后
var destinations = context . Sources . ProjectToType < Destination >(). ToList ();
}
将 Dto
映射到已存在的 Entity
复制 var entity = _testRepository . GetFirstOrDefault (predicate : u => u . Id == 1 );
var dto = new Dto () { Name = "Monk" , Age = 27 };
dto . Adapt (entity); // 这时,Entity会自动更新 Name和Age属性,其他的保持不变
注意 如果 Dto
中某些值为 Null
,默认也会将 Null
值更新到 Entity
,这可能不是我们想要的!!! 所以,我们需要手动配置一下,Null
值不需要映射。
复制 config . ForType < Dto , Entity >()
. IgnoreNullValues ( true );
更多 Mapster 可查看官方文档 。