Day26:角色管理 API 完整教程(CRUD + 分配菜单 + 事务)
一、今日学习内容角色CRUD接口给角色分配菜单事务 多对多查询角色已关联的菜单列表Service Controller 完整实现权限关联逻辑二、先给你 DTO必须新建Application/Dtos/RoleDtos.cspublic class RoleCreateDto { public string RoleName { get; set; } public string RoleCode { get; set; } public int Sort { get; set; } public int Status { get; set; } } public class RoleUpdateDto { public long Id { get; set; } public string RoleName { get; set; } public string RoleCode { get; set; } public int Sort { get; set; } public int Status { get; set; } } // 角色分配菜单 DTO public class AssignMenuDto { public long RoleId { get; set; } public Listlong MenuIds { get; set; } }Application/Vos/RoleVo.cspublic class RoleVo { public long Id { get; set; } public string Name { get; set; } public string Code { get; set; } public int Sort { get; set; } public int Status { get; set; } public DateTime CreateTime { get; set; } }三、AutoMapper 映射加到你的 ProfileCreateMapRoleCreateDto, Role(); CreateMapRoleUpdateDto, Role(); CreateMapRole, RoleVo();四、IRoleService 接口public interface IRoleService { TaskRListRoleVo GetListAsync(); TaskRRoleVo GetByIdAsync(long id); TaskRstring AddAsync(RoleCreateDto dto); TaskRstring UpdateAsync(RoleUpdateDto dto); TaskRstring DeleteAsync(long id); TaskRstring AssignMenuAsync(AssignMenuDto dto); }五、RoleService 完整实现核心业务public class RoleService : IRoleService { private readonly IUnitOfWork _uow; private readonly IMapper _mapper; public RoleService(IUnitOfWork uow, IMapper mapper) { _uow uow; _mapper mapper; } // 列表 public async TaskRListRoleVo GetListAsync() { var list await _uow.RoleRepository.GetAllAsync(); var voList _mapper.MapListRoleVo(list); return RListRoleVo.Success(voList); } // 详情 public async TaskRRoleVo GetByIdAsync(long id) { var role await _uow.RoleRepository.FirstOrDefaultAsync(x x.Id id); if (role null) return RRoleVo.Fail(角色不存在); return RRoleVo.Success(_mapper.MapRoleVo(role)); } // 新增 public async TaskRstring AddAsync(RoleCreateDto dto) { var isExist await _uow.RoleRepository.AnyAsync(x x.Code dto.Code); if (isExist) return Rstring.Fail(角色编码已存在); var role _mapper.MapRole(dto); await _uow.RoleRepository.AddAsync(role); await _uow.SaveChangesAsync(); return Rstring.Success(新增成功); } // 修改 public async TaskRstring UpdateAsync(RoleUpdateDto dto) { var role await _uow.RoleRepository.FirstOrDefaultAsync(x x.Id dto.Id); if (role null) return Rstring.Fail(角色不存在); _mapper.Map(dto, role); await _uow.SaveChangesAsync(); return Rstring.Success(修改成功); } // 删除 public async TaskRstring DeleteAsync(long id) { // 检查是否有用户在使用 var hasUser await _uow.UserRole.AnyAsync(x x.RoleId id); if (hasUser) return Rstring.Fail(该角色已分配用户无法删除); await _uow.RoleMenu.DeleteAsync(x x.RoleId id); await _uow.RoleRepository.DeleteAsync(id); await _uow.SaveChangesAsync(); return Rstring.Success(删除成功); } // // 核心角色分配菜单事务 // public async TaskRstring AssignMenuAsync(AssignMenuDto dto) { using (await _uow.BeginTransactionAsync()) { try { // 1. 删除原有权限 await _uow.RoleMenuRepository.DeleteBatchAsync(x x.RoleId dto.RoleId); // 2. 添加新权限 foreach (var menuId in dto.MenuIds) { await _uow.RoleMenuRepository.AddAsync(new RoleMenu { RoleId dto.RoleId, MenuId menuId }); } await _uow.SaveChangesAsync(); return Rstring.Sucess(分配成功); } catch (Exception ex) { await _uow.RollbackAsync(); throw new Exception(Transaction failed, ex); } } } }六、RoleController 接口[ApiController] [Route(api/[controller])] [Authorize] public class RoleController : ControllerBase { private readonly IRoleService _roleService; public RoleController(IRoleService roleService) { _roleService roleService; } [HttpGet(list)] public async TaskActionResultRListRoleVo List() { return await _roleService.GetListAsync(); } [HttpGet({id})] public async TaskActionResultRRoleVo Get(long id) { return await _roleService.GetByIdAsync(id); } [HttpPost(add)] public async TaskActionResultRstring Add(RoleCreateDto dto) { return await _roleService.AddAsync(dto); } [HttpPut(update)] public async TaskActionResultRstring Update(RoleUpdateDto dto) { return await _roleService.UpdateAsync(dto); } [HttpDelete({id})] public async TaskActionResultRstring Delete(long id) { return await _roleService.DeleteAsync(id); } // 分配菜单 [HttpPost(assignMenu)] public async TaskActionResultRstring AssignMenu(AssignMenuDto dto) { return await _roleService.AssignMenuAsync(dto); } }七、必须注册服务builder.Services.AddScopedIRoleService, RoleService();八、今日练习完成标准✅ 角色 CRUD 接口全部完成✅ 角色分配菜单先删后增事务保证✅ 角色不能重复编码✅ 删除角色前检查是否被用户使用✅ 全部使用 DTO/VO✅ AutoMapper 映射✅ 接口需要登录[Authorize]