环境: abp vnext(4.2) , Mapster(7.5)
一、 使用 Mapster作为默认对象转换
Abp Vnext 默认使用 AutoMapper(9.0+) 作为对象转换器,比较麻烦的一点是需要不断的配置 AutoMapper的Profile,DTO比较多的话个人觉得还是比较麻烦的,尤其是Web层还有ViewModel到DTO的转换,那么能不能使用Mapster作为默认转换器呢,Mapster不需要注册对象的转换,可以省下不少创建Profile的时间,而且据官方测试效率也比AutoMapper高,答案是可以的,而且很容易。可以参考官方文档:Object To Object Mapping 说明。
第一步:实现 IObjectMapper
//[Dependency(lifetime: ServiceLifetime.Transient, TryRegister = true)] public class MapsterObjectMapper<TSource, TDestination> : IObjectMapper<TSource, TDestination>//, ITransientDependency { public TDestination Map(TSource source) { return source.Adapt<TDestination>( ); } public TDestination Map(TSource source, TDestination destination) { return source.Adapt<TSource, TDestination>(destination); } }
注意,我注释了[Dependency] 和ITransientDependency ,因为按官方文档,这两个类需实现其中一个,框架就会自动注册Services,但是我没测试成功。所以下一步就是在Module代码中注册Services。
第二步: 在需要使用的Module中注册 Services:
context.Services.AddTransient(typeof(IObjectMapper<,>), typeof(MapsterObjectMapper<,>));
如此,便注册了泛型的对象转换器。
二、 切换Mapster存在的问题
那么,官方为什么不直接使用Mapster呢?我觉得大概是会破坏DDD的设计。一般abp vnext 里的Entity 结构如下
public partial class TestClass: AuditedEntity<Guid> { public string Keyword1 { get; set; } public string Keyword2 { get; set; } protected TestClass() { } public TestClass( Guid id, string keyword1, string keyword2, ) : base(id) { Keyword1 = keyword1; Keyword2 = keyword2; }
这个对象有一个protectd 的构造函数用于反射实例化,一个多参数的构造函数用于控制使用者创建对象的完整性,AutoMapper是能支持这个结构的。Mapster却不能,
它需要一个公开的无实参构造函数,或者配置有参的构造函数,参考官方文档: Map to constructor 。对于有参构造函数,由于 Guid id 这个字段,而我的DTO不包含Id 字段,Mapster无法匹配创建Entity,所以也会报错。
对于Mapster的使用,我感觉有两种方式
1. 只在 Web项目使用,由ViewModel到DTO的互相转换
2. Service层也使用,但是Entity的有参构造函数不能有DTO不包含的字段