using Microsoft.EntityFrameworkCore; using TakeoutSaaS.Domain.Identity.Entities; using TakeoutSaaS.Domain.Identity.Repositories; namespace TakeoutSaaS.Infrastructure.Identity.Persistence; /// /// EF 角色-权限仓储。 /// public sealed class EfRolePermissionRepository(IdentityDbContext dbContext) : IRolePermissionRepository { /// /// 根据角色 ID 集合获取角色权限映射。 /// /// 租户 ID。 /// 角色 ID 集合。 /// 取消标记。 /// 角色权限映射列表。 public async Task> GetByRoleIdsAsync(long tenantId, IEnumerable roleIds, CancellationToken cancellationToken = default) { // 1. 查询角色权限映射 var mappings = await dbContext.RolePermissions .AsNoTracking() .Where(x => x.TenantId == tenantId && x.DeletedAt == null && roleIds.Contains(x.RoleId)) .ToListAsync(cancellationToken); // 2. (空行后) 返回只读列表 return mappings; } /// /// 批量新增角色权限。 /// /// 角色权限集合。 /// 取消标记。 /// 异步任务。 public async Task AddRangeAsync(IEnumerable rolePermissions, CancellationToken cancellationToken = default) { // 1. 转为数组便于计数 var toAdd = rolePermissions as RolePermission[] ?? rolePermissions.ToArray(); if (toAdd.Length == 0) { return; } // 2. 批量插入 await dbContext.RolePermissions.AddRangeAsync(toAdd, cancellationToken); } /// /// 替换指定角色的权限集合。 /// /// 租户 ID。 /// 角色 ID。 /// 权限 ID 集合。 /// 取消标记。 /// 异步任务。 public async Task ReplaceRolePermissionsAsync(long tenantId, long roleId, IEnumerable permissionIds, CancellationToken cancellationToken = default) { // 1. 使用执行策略保证可靠性 var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken); // 1. 删除旧记录(原生 SQL,避免跟踪干扰) await dbContext.Database.ExecuteSqlRawAsync( "DELETE FROM \"role_permissions\" WHERE \"TenantId\" = {0} AND \"RoleId\" = {1};", parameters: new object[] { tenantId, roleId }, cancellationToken: cancellationToken); // 2. 插入新记录(防重复) foreach (var permissionId in permissionIds.Distinct()) { await dbContext.Database.ExecuteSqlRawAsync( "INSERT INTO \"role_permissions\" (\"TenantId\",\"RoleId\",\"PermissionId\",\"CreatedAt\",\"CreatedBy\",\"UpdatedAt\",\"UpdatedBy\",\"DeletedAt\",\"DeletedBy\") VALUES ({0},{1},{2},NOW(),NULL,NULL,NULL,NULL,NULL) ON CONFLICT DO NOTHING;", parameters: new object[] { tenantId, roleId, permissionId }, cancellationToken: cancellationToken); } await trx.CommitAsync(cancellationToken); }); } /// /// 保存仓储变更。 /// /// 取消标记。 /// 保存任务。 public Task SaveChangesAsync(CancellationToken cancellationToken = default) => dbContext.SaveChangesAsync(cancellationToken); }