控制台程序为例,展示该demo
一、安装Nuget包
二、文件结构
三、AutoMapperProfile.cs(映射规则)
【基础demo】
【需求】Student 类的 Name 字段映射到 Teacher 类的 FullName 字段
using AutoMapper;
namespace ConsoleApp1
{
public class AutoMapperProfile : Profile
{
public AutoMapperProfile()
{
CreateMap<Student, Teacher>()
.ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.Name));//配置不同名的字段映射
//其他字段:字段名称一样的自动映射
}
}
}
【解释和说明】
【映射检查】
CreateMap<T,V>()中,允许入参控制是否进行映射检查
//映射规则:例如可以传入 CreateMap<源类,目标类>(MemberList.Source)
public enum MemberList
{
Destination,//CreateMap不传参默认也是这种,【目标类有未被映射成员=>报错】
Source,//【源类有未映射出去的成员=>报错】
None//【源类,目标类是否被映射都不报错】
}
【转换名称后映射】
例如以下规则,就是Student(Name= "John")=>Teacher (FullName ="新名字John")
.ForMember(dest => dest.FullName, opt => opt.MapFrom(src => "新名字" + src.Name));
【双向映射】
CreateMap<Student, Teacher>().ReverseMap();
【多字段映射写法】
CreateMap<Student, Teacher>()
.ForMember(dest => dest.FullName, opt => opt.MapFrom(src => src.Name))
.ForMember(略)
.ForMember(略);
【字段的映射忽略】(避免报错)
假如public string Name { get; } (没有set方法)会报错
解决方案一(封装方法判断此情况,自动跳过):
CreateMap<Student, Teacher>()
.IgnoreAllPropertiesWithAnInaccessibleSetter()
.IgnoreAllSourcePropertiesWithAnInaccessibleSetter(); // 忽略所有设置器不可访问的属性
解决方案二(不选择字段映射到FullName):
CreateMap<Student, Teacher>()
.ForMember(dest => dest.FullName, opt => opt.Ignore()); // 明确忽略特定属性
四、Model.cs(实体模型)
namespace ConsoleApp1
{
public class Model
{
}
public class Student
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
public class Teacher
{
public int Id { get; set; }
public string FullName { get; set; }
public int Age { get; set; }
}
}
五、Program.cs(程序入口)
using AutoMapper;
namespace ConsoleApp1
{
internal class Program
{
static void Main(string[] args)
{
// 配置规则
var configuration = new MapperConfiguration(cfg =>
{
cfg.AddProfile<AutoMapperProfile>();
});
// 创建映射器
IMapper mapper = configuration.CreateMapper();
// 创建学生实体
var student = new Student
{
Id = 1,
Name = "小苏",
Age = 20
};
// 映射成老师
var teacher = mapper.Map<Teacher>(student);
Console.WriteLine($"Teacher: Id={teacher.Id}, FullName={teacher.FullName}, Age={teacher.Age}");
//输出:Teacher: Id=1, FullName=小苏, Age=20
}
}
}
六、ABP框架下实体映射的三种方式
方案一二(注入):
[Route("api/books")]
public class BookAppService : ApplicationService, IBookAppService
{
private readonly IBookService _bookService;
private readonly IObjectMapper _objectMapper;
public BookAppService(
IBookService bookService,
IObjectMapper objectMapper
)
{
_bookService = bookService;
_objectMapper = objectMapper;
}
[Route("getbookbybll")]
[HttpGet]
public async Task<List<BookDto>> GetListByBLLAsync()
{
List<BookDto> list = await _bookService.GetBooks();//假设有一个服务可以获取List<BookDto>
List<Book> test1 = ObjectMapper.Map<List<BookDto>,List<Book>>(list);//方案一,底层接口或者WebApi控制器继承ApplicationService,直接使用ObjectMapper(前提:应用层配置好映射关系CreateMap)
List<Book> test2 = _objectMapper.Map<List<BookDto>,List<Book>>(list);//方案二,注入IObjectMapper使用(前提:应用层配置好映射关系CreateMap)
return list;
}
}
方案三:
var config = new MapperConfiguration(cfg => cfg.AddProfile<XXXXXXXXAutoMapperProfile>());//XXXXXXXXAutoMapperProfile 配置CreateMap规则
var list = config.CreateMapper().Map<List<源类>, List<目标类>>(list); //list是源类的列表数据
七、常见问题
1.ABP框架中忽略id映射
ABP框架中Id不映射是如何做到的?
方案一:满足以下两个条件:
①目标类继承了DOEntity时,Id只允许get不允许set。
public class DOEntity : DOEntity<int>
{
[Required]
[Column("id")]
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public override int Id { get; protected set; }
}
②设置了忽略列,防止①带来报错
.IgnoreAllPropertiesWithAnInaccessibleSetter()
.IgnoreAllSourcePropertiesWithAnInaccessibleSetter()
方案二:直接用语法忽略
CreateMap<T, V>()
.ForMember(dest => dest.Id, opt => opt.Ignore());
2.某个映射失败
请逐步排查:
①是否定义了CreateMap
若定义了,CreateMap的映射检查(三选一)是否满足
②是否调用时写错了类名
3.映射语法报错
以下两种写法是有区别的,CreateMap只创建实体即可,映射则要分清实体和列表。下面是调用的例子:
config.CreateMapper().Map<源类>, 目标类>(list);
config.CreateMapper().Map<List<源类>, List<目标类>>(list);