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);
});
}
}