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