using Microsoft.EntityFrameworkCore; using TakeoutSaaS.Domain.Identity.Entities; using TakeoutSaaS.Domain.Identity.Repositories; namespace TakeoutSaaS.Infrastructure.Identity.Persistence; /// /// 角色模板仓储实现。 /// public sealed class EfRoleTemplateRepository(IdentityDbContext dbContext) : IRoleTemplateRepository { /// /// 获取全部角色模板,可选按启用状态过滤。 /// /// 是否启用过滤。 /// 取消标记。 /// 角色模板列表。 public Task> GetAllAsync(bool? isActive, CancellationToken cancellationToken = default) { // 1. 构建基础查询 var query = dbContext.RoleTemplates.AsNoTracking(); if (isActive.HasValue) { // 2. 按启用状态过滤 query = query.Where(x => x.IsActive == isActive.Value); } // 3. 排序并返回 return query .OrderBy(x => x.TemplateCode) .ToListAsync(cancellationToken) .ContinueWith(t => (IReadOnlyList)t.Result, cancellationToken); } /// /// 根据模板编码获取角色模板。 /// /// 模板编码。 /// 取消标记。 /// 角色模板或 null。 public Task FindByCodeAsync(string templateCode, CancellationToken cancellationToken = default) { // 1. 规范化编码 var normalized = templateCode.Trim(); // 2. 查询模板 return dbContext.RoleTemplates.AsNoTracking().FirstOrDefaultAsync(x => x.TemplateCode == normalized, cancellationToken); } /// /// 获取指定模板的权限集合。 /// /// 模板 ID。 /// 取消标记。 /// 模板权限列表。 public Task> GetPermissionsAsync(long roleTemplateId, CancellationToken cancellationToken = default) { // 1. 查询模板权限 return dbContext.RoleTemplatePermissions.AsNoTracking() .Where(x => x.RoleTemplateId == roleTemplateId) .ToListAsync(cancellationToken) .ContinueWith(t => (IReadOnlyList)t.Result, cancellationToken); } /// /// 获取多个模板的权限集合。 /// /// 模板 ID 集合。 /// 取消标记。 /// 模板到权限的字典。 public async Task>> GetPermissionsAsync(IEnumerable roleTemplateIds, CancellationToken cancellationToken = default) { // 1. 去重 ID var ids = roleTemplateIds.Distinct().ToArray(); if (ids.Length == 0) { return new Dictionary>(); } // 2. 批量查询权限 var permissions = await dbContext.RoleTemplatePermissions.AsNoTracking() .Where(x => ids.Contains(x.RoleTemplateId)) .ToListAsync(cancellationToken); // 3. 组装字典 return permissions .GroupBy(x => x.RoleTemplateId) .ToDictionary(g => g.Key, g => (IReadOnlyList)g.ToList()); } /// /// 新增角色模板并配置权限。 /// /// 角色模板实体。 /// 权限编码集合。 /// 取消标记。 /// 异步任务。 public async Task AddAsync(RoleTemplate template, IEnumerable permissionCodes, CancellationToken cancellationToken = default) { // 1. 规范化模板字段 template.TemplateCode = template.TemplateCode.Trim(); template.Name = template.Name.Trim(); // 2. 保存模板 await dbContext.RoleTemplates.AddAsync(template, cancellationToken); // 3. 替换权限 await ReplacePermissionsInternalAsync(template, permissionCodes, cancellationToken); } /// /// 更新角色模板并重置权限。 /// /// 角色模板实体。 /// 权限编码集合。 /// 取消标记。 /// 异步任务。 public async Task UpdateAsync(RoleTemplate template, IEnumerable permissionCodes, CancellationToken cancellationToken = default) { // 1. 规范化模板字段 template.TemplateCode = template.TemplateCode.Trim(); template.Name = template.Name.Trim(); // 2. 更新模板 dbContext.RoleTemplates.Update(template); // 3. 重置权限 await ReplacePermissionsInternalAsync(template, permissionCodes, cancellationToken); } /// /// 删除角色模板及其权限。 /// /// 模板 ID。 /// 取消标记。 /// 异步任务。 public async Task DeleteAsync(long roleTemplateId, CancellationToken cancellationToken = default) { // 1. 查询模板 var entity = await dbContext.RoleTemplates.FirstOrDefaultAsync(x => x.Id == roleTemplateId, cancellationToken); if (entity != null) { // 2. 删除关联权限 var permissions = dbContext.RoleTemplatePermissions.Where(x => x.RoleTemplateId == roleTemplateId); dbContext.RoleTemplatePermissions.RemoveRange(permissions); // 3. 删除模板 dbContext.RoleTemplates.Remove(entity); } } /// /// 保存仓储变更。 /// /// 取消标记。 /// 保存任务。 public Task SaveChangesAsync(CancellationToken cancellationToken = default) => dbContext.SaveChangesAsync(cancellationToken); private async Task ReplacePermissionsInternalAsync(RoleTemplate template, IEnumerable permissionCodes, CancellationToken cancellationToken) { // 1. 使用执行策略保证一致性 var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken); // 1. 确保模板已持久化,便于 FK 正确填充 if (!dbContext.Entry(template).IsKeySet || template.Id == 0) { await dbContext.SaveChangesAsync(cancellationToken); } // 2. 归一化权限编码 var normalized = permissionCodes .Where(code => !string.IsNullOrWhiteSpace(code)) .Select(code => code.Trim()) .Distinct(StringComparer.OrdinalIgnoreCase) .ToArray(); // 3. 清空旧权限(原生 SQL 避免跟踪干扰) await dbContext.Database.ExecuteSqlRawAsync( "DELETE FROM \"role_template_permissions\" WHERE \"RoleTemplateId\" = {0};", parameters: new object[] { template.Id }, cancellationToken: cancellationToken); // 4. 插入新权限(ON CONFLICT DO NOTHING 防御重复) foreach (var code in normalized) { await dbContext.Database.ExecuteSqlRawAsync( "INSERT INTO \"role_template_permissions\" (\"RoleTemplateId\",\"PermissionCode\",\"CreatedAt\",\"CreatedBy\",\"UpdatedAt\",\"UpdatedBy\",\"DeletedAt\",\"DeletedBy\") VALUES ({0},{1},NOW(),NULL,NULL,NULL,NULL,NULL) ON CONFLICT DO NOTHING;", parameters: new object[] { template.Id, code }, cancellationToken: cancellationToken); } await trx.CommitAsync(cancellationToken); }); } }