配置 AutoMapper 关系映射
在上一节ToDoController 控制器,或 IToDoService服务接口中,方法的传参都是直接传的实体类。但在实际开发过程中,这样是不允许的。标准且规范的做法是,定义一个数据传输层,即Dto层。
一.在MyToDo.Api 项目中安装 Auto Mapper
二. 在MyToDo.Shared 项目中创建一个Dtos文件夹,存放Dto文件
1. 创建 BaseDto 基类,用于存放共用属性。
cs
public class BaseDto
{
public int Id { get; set; }
}
2. 创建待办事项 Dto类,并继承自 BaseDto 基类
cs
/// <summary>
/// 待办事项数据实体
/// </summary>
public class ToDoDto:BaseDto
{
public string Title { get; set; }
public string Content { get; set; }
public int Status { get; set; }
}
3.由于我们的客户端是Wpf 项目,各属性需要实现通知绑定 。所以 BaseDto类需要进行修改,并且要继承自 INotifyPropertyChanged 接口。同时还要实现一个通知绑定的方法。
cs
public class BaseDto:INotifyPropertyChanged
{
public int Id { get; set; }
public event PropertyChangedEventHandler? PropertyChanged;
/// <summary>
/// CallerMemberName 是一个自动获取传入名称的属性
/// </summary>
/// <param name="propertyName"></param>
public void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this,new PropertyChangedEventArgs(propertyName));
}
}
4.接着,要需要再修改 ToDoDto ,让它具备实现属性绑定通知功能。
cs
/// <summary>
/// 待办事项数据实体
/// </summary>
public class ToDoDto:BaseDto
{
private string title;
private string content;
private int status;
public string Title
{
get { return title; }
set { title = value; OnPropertyChanged(); }
}
public string Content
{
get { return content; }
set { content = value; OnPropertyChanged(); }
}
public int Status
{
get { return status; }
set { status = value; OnPropertyChanged(); }
}
}
三.把实体类(ToDo)和定义的数据传输类(ToDoDto) 进行关系映射
1.在 MyToDo.Api 项目中,创建一个 Extensions 扩展文件夹。再创建一个 AutoMapperProFile 类,并且继承自 MapperConfigurationExpression,该类用于配置所有实体类和数据传输类的映射关系。
cs
public class AutoMapperProFile:MapperConfigurationExpression
{
public AutoMapperProFile()
{
/// 实体类和数据传输类进行映射
CreateMap<ToDo, ToDoDto>().ReverseMap();
}
}
- ReverseMap 表示两者之间可以互相进行转换。
四.修改 ToDoController 控制器传参和IToDoService 服务传参
1. IToDoService接口类传入的ToDo实体改成ToDoDto
cs
public interface IToDoService:IBaseService<ToDoDto>
{
}
2.ToDoService 服务实现类,所有传入参数是ToDo实体,需全部换成ToDoDto。并且需要在构造函数中注入 IMapper 接口。
cs
/// <summary>
/// 待办事项的实现
/// </summary>
public class ToDoService : IToDoService
{
private readonly IUnitOfWork work;
private readonly IMapper mapper;
public ToDoService(IUnitOfWork work,IMapper mapper)
{
this.work = work;
this.mapper = mapper;
}
public async Task<ApiResponse> AddAsync(ToDoDto model)
{
try
{
var doto= mapper.Map<ToDo>(model);//进行数据映射转换
await work.GetRepository<ToDo>().InsertAsync(doto);
if (await work.SaveChangesAsync() > 0) //保存成功
{
return new ApiResponse(true, model); //返回true,并把添加的实体返回
}
return new ApiResponse("添加数据失败");
}
catch (Exception ex)
{
return new ApiResponse(ex.Message);
}
}
public async Task<ApiResponse> DeleteAsync(int id)
{
try
{
var repository= work.GetRepository<ToDo>();//获取仓储
//删除之前,先进行查询
var todo = await repository.GetFirstOrDefaultAsync(predicate:x=>x.Id.Equals(id));
repository.Delete(todo);
if (await work.SaveChangesAsync() > 0) //删除成功
{
return new ApiResponse(true, "删除成功");
}
return new ApiResponse("删除数据失败");
}
catch (Exception ex)
{
return new ApiResponse(ex.Message);
}
}
public async Task<ApiResponse> GetAllAsync()
{
try
{
var todos= await work.GetRepository<ToDo>().GetAllAsync();
return new ApiResponse(true, todos); //返回true,并返回所有数据
}
catch (Exception ex)
{
return new ApiResponse(ex.Message);
}
}
public async Task<ApiResponse> GetSingleAsync(int id)
{
try
{
var todo= await work.GetRepository<ToDo>().GetFirstOrDefaultAsync(predicate: x => x.Id.Equals(id));
return new ApiResponse(true, todo); //把找到的数据返回
}
catch (Exception ex)
{
return new ApiResponse(ex.Message);
}
}
public async Task<ApiResponse> UpdateAsync(ToDoDto model)
{
try
{
var dbdoto = mapper.Map<ToDo>(model);
var repository = work.GetRepository<ToDo>();//获取仓储
//更新之前,先拿到要更新的数据
var todo = await repository.GetFirstOrDefaultAsync(predicate: x => x.Id.Equals(dbdoto.Id));
todo.Title = dbdoto.Title;
todo.Content = dbdoto.Content;
todo.Status = dbdoto.Status;
todo.UpdateDate = DateTime.Now;
repository.Update(todo);
if (await work.SaveChangesAsync() > 0) //更新成功
{
return new ApiResponse(true, "更新成功");
}
return new ApiResponse("更新数据失败");
}
catch (Exception ex)
{
return new ApiResponse(ex.Message);
}
}
}
- IMapper 接口里的 Map 方法,用于 Dto和实体类之间的数据映射转换
3.把ToDoController 控制器传入的ToDo实体改成ToDoDto
cs
[ApiController]
[Route("api/[controller]/[action]")]
public class ToDoController:ControllerBase
{
private readonly IToDoService service;
public ToDoController(IToDoService service)
{
this.service = service;
}
[HttpGet]
public async Task<ApiResponse> Get(int id)=> await service.GetSingleAsync(id);
[HttpGet]
public async Task<ApiResponse> GetAll() => await service.GetAllAsync();
[HttpPost]
public async Task<ApiResponse> Add([FromBody]ToDoDto model) => await service.AddAsync(model);
[HttpPost]
public async Task<ApiResponse> Update([FromBody] ToDoDto model) => await service.UpdateAsync(model);
[HttpDelete]
public async Task<ApiResponse> Delete(int id) => await service.DeleteAsync(id);
}
五.最后,需要在Program.cs 中,进行注册 AutoMapper 服务
cs
//注入AutoMapper
builder.Services.AddSingleton(new MapperConfiguration(config =>
{
config.AddProfile(new AutoMapperProFile());
}).CreateMapper());