mapster可直接替代automapper,但需正确安装mapster与mapster.dependencyinjection包,并在program.cs中调用builder.services.addmapster();禁用typeadapterconfig.globalsettings,优先使用di注册的imapper;adapt()不适用于iqueryable,必须用projecttotype()配合mapster.efcore;私有成员映射需显式配置ignorenonpublic,且aot下可能运行时失效。

Mapster 能直接替代 AutoMapper,且大部分 Adapt<t>()</t> 调用无需修改——但不初始化、不配 DI、乱用 ProjectToType() 就会立刻报错或性能崩盘。
安装与 DI 注册必须一步到位
只装 Mapster 包,IMapper 注入一定失败,报错 InvalidOperationException: No service for type 'IMapper' has been registered。原因是你漏了 Mapster.DependencyInjection。
正确操作只有三步:
- 运行
dotnet add package Mapster - 运行
dotnet add package Mapster.DependencyInjection - 在
Program.cs中调用builder.Services.AddMapster()(无参数即可)
别碰 TypeAdapterConfig.GlobalSettings 做全局配置——它不是线程安全的,多租户或热重载场景下会被覆盖;DI 注册的 IMapper 实例才是可测试、可作用域控制的正解。
Adapt<t>()</t> 和 IMapper.Map<t>()</t> 别混用
Adapt<t>()</t> 是扩展方法,走静态缓存;IMapper.Map<t>()</t> 走 DI 实例,支持 Scoped 生命周期和局部配置。两者行为看似一样,但关键差异藏在细节里:
- 对
IQueryable<t></t>调用Adapt<t>()</t>会强制执行ToList(),丢失延迟加载优势 -
Adapt<t>()</t>不识别你用TypeAdapterConfig.ForType()写的局部映射规则,除非显式传入 config 实例 - 泛型集合如
List<user></user>→List<userdto></userdto>默认支持,但若 DTO 里有DateTime?映射到string,没配转换器就抛NotSupportedException
数据库查询必须用 ProjectToType<t>()</t>,不能用 Adapt<t>()</t>
这是最常踩的性能坑:把 EF Core 的 IQueryable<userentity></userentity> 直接 .Adapt<list>>()</list>,结果全表查出来再内存转换,SQL 层完全没优化。
正确做法是:
- 先安装
Mapster.EFCore包 - 用
queryable.ProjectToType<userdto>()</userdto>(注意不是Adapt) - 确保目标属性能被 EF Core 表达式树解析——比如
src.CreatedAt.ToString("yyyy-MM-dd")不行,但EF.Functions.DatePart("year", src.CreatedAt)可以
如果误把 ProjectToType<t>()</t> 用在普通 List<t></t> 上,会立即抛出 InvalidOperationException: The source IQueryable doesn't implement IAsyncEnumerable。
私有字段、init 属性默认不映射
遇到 public string Name { get; init; } 或 public int Age { get; private set; },Mapster 默认跳过,目标值始终为 default。这不是 bug,是设计选择。
要启用非公开成员写入,必须显式配置:
- 全局:启动时加
TypeAdapterConfig.GlobalSettings.Default.IgnoreNonPublic = true - 局部:用
TypeAdapterConfig<tsource tdest>.NewConfig().IgnoreNonPublic(true)</tsource>
注意:IgnoreNonPublic = true 后底层走反射赋值,.NET 6+ AOT 编译可能失败,上线前务必验证。
真正卡住人的地方往往不是“怎么配”,而是“什么时候必须配”——比如 ProjectToType<t>()</t> 必须依赖 Mapster.EFCore,而 IgnoreNonPublic 在 AOT 下失效却不会编译报错,只会在运行时静默失败。











