Files
TakeoutSaaS.AdminApi/src/Infrastructure/TakeoutSaaS.Infrastructure/Identity/Persistence/EfRoleTemplateRepository.cs

194 lines
8.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Microsoft.EntityFrameworkCore;
using TakeoutSaaS.Domain.Identity.Entities;
using TakeoutSaaS.Domain.Identity.Repositories;
namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
/// <summary>
/// 角色模板仓储实现。
/// </summary>
public sealed class EfRoleTemplateRepository(IdentityDbContext dbContext) : IRoleTemplateRepository
{
/// <summary>
/// 获取全部角色模板,可选按启用状态过滤。
/// </summary>
/// <param name="isActive">是否启用过滤。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>角色模板列表。</returns>
public Task<IReadOnlyList<RoleTemplate>> 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<RoleTemplate>)t.Result, cancellationToken);
}
/// <summary>
/// 根据模板编码获取角色模板。
/// </summary>
/// <param name="templateCode">模板编码。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>角色模板或 null。</returns>
public Task<RoleTemplate?> FindByCodeAsync(string templateCode, CancellationToken cancellationToken = default)
{
// 1. 规范化编码
var normalized = templateCode.Trim();
// 2. 查询模板
return dbContext.RoleTemplates.AsNoTracking().FirstOrDefaultAsync(x => x.TemplateCode == normalized, cancellationToken);
}
/// <summary>
/// 获取指定模板的权限集合。
/// </summary>
/// <param name="roleTemplateId">模板 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>模板权限列表。</returns>
public Task<IReadOnlyList<RoleTemplatePermission>> GetPermissionsAsync(long roleTemplateId, CancellationToken cancellationToken = default)
{
// 1. 查询模板权限
return dbContext.RoleTemplatePermissions.AsNoTracking()
.Where(x => x.RoleTemplateId == roleTemplateId)
.ToListAsync(cancellationToken)
.ContinueWith(t => (IReadOnlyList<RoleTemplatePermission>)t.Result, cancellationToken);
}
/// <summary>
/// 获取多个模板的权限集合。
/// </summary>
/// <param name="roleTemplateIds">模板 ID 集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>模板到权限的字典。</returns>
public async Task<IDictionary<long, IReadOnlyList<RoleTemplatePermission>>> GetPermissionsAsync(IEnumerable<long> roleTemplateIds, CancellationToken cancellationToken = default)
{
// 1. 去重 ID
var ids = roleTemplateIds.Distinct().ToArray();
if (ids.Length == 0)
{
return new Dictionary<long, IReadOnlyList<RoleTemplatePermission>>();
}
// 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<RoleTemplatePermission>)g.ToList());
}
/// <summary>
/// 新增角色模板并配置权限。
/// </summary>
/// <param name="template">角色模板实体。</param>
/// <param name="permissionCodes">权限编码集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>异步任务。</returns>
public async Task AddAsync(RoleTemplate template, IEnumerable<string> 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);
}
/// <summary>
/// 更新角色模板并重置权限。
/// </summary>
/// <param name="template">角色模板实体。</param>
/// <param name="permissionCodes">权限编码集合。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>异步任务。</returns>
public async Task UpdateAsync(RoleTemplate template, IEnumerable<string> 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);
}
/// <summary>
/// 删除角色模板及其权限。
/// </summary>
/// <param name="roleTemplateId">模板 ID。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>异步任务。</returns>
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);
}
}
/// <summary>
/// 保存仓储变更。
/// </summary>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>保存任务。</returns>
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
=> dbContext.SaveChangesAsync(cancellationToken);
private async Task ReplacePermissionsInternalAsync(RoleTemplate template, IEnumerable<string> 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);
});
}
}