using Microsoft.EntityFrameworkCore; using TakeoutSaaS.Domain.Identity.Entities; using TakeoutSaaS.Domain.Identity.Repositories; namespace TakeoutSaaS.Infrastructure.Identity.Persistence; /// /// EF 用户-角色仓储。 /// public sealed class EfUserRoleRepository(IdentityDbContext dbContext) : IUserRoleRepository { /// /// 根据用户 ID 集合获取用户角色映射。 /// /// 租户 ID。 /// 用户 ID 集合。 /// 取消标记。 /// 用户角色映射列表。 public Task> GetByUserIdsAsync(long tenantId, IEnumerable userIds, CancellationToken cancellationToken = default) => dbContext.UserRoles.AsNoTracking() .Where(x => x.TenantId == tenantId && userIds.Contains(x.UserId)) .ToListAsync(cancellationToken) .ContinueWith(t => (IReadOnlyList)t.Result, cancellationToken); /// /// 获取指定用户的角色集合。 /// /// 租户 ID。 /// 用户 ID。 /// 取消标记。 /// 用户角色列表。 public Task> GetByUserIdAsync(long tenantId, long userId, CancellationToken cancellationToken = default) => dbContext.UserRoles.AsNoTracking() .Where(x => x.TenantId == tenantId && x.UserId == userId) .ToListAsync(cancellationToken) .ContinueWith(t => (IReadOnlyList)t.Result, cancellationToken); /// /// 替换指定用户的角色集合。 /// /// 租户 ID。 /// 用户 ID。 /// 角色 ID 集合。 /// 取消标记。 /// 异步任务。 public async Task ReplaceUserRolesAsync(long tenantId, long userId, IEnumerable roleIds, CancellationToken cancellationToken = default) { // 1. 使用执行策略保障一致性 var strategy = dbContext.Database.CreateExecutionStrategy(); await strategy.ExecuteAsync(async () => { await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken); // 2. 读取当前角色映射 var existing = await dbContext.UserRoles .Where(x => x.TenantId == tenantId && x.UserId == userId) .ToListAsync(cancellationToken); // 3. 清空并保存 dbContext.UserRoles.RemoveRange(existing); await dbContext.SaveChangesAsync(cancellationToken); // 4. 构建新映射 var toAdd = roleIds.Distinct().Select(roleId => new UserRole { TenantId = tenantId, UserId = userId, RoleId = roleId }); // 5. 批量新增并保存 await dbContext.UserRoles.AddRangeAsync(toAdd, cancellationToken); await dbContext.SaveChangesAsync(cancellationToken); await trx.CommitAsync(cancellationToken); }); } /// /// 保存仓储变更。 /// /// 取消标记。 /// 保存任务。 public Task SaveChangesAsync(CancellationToken cancellationToken = default) => dbContext.SaveChangesAsync(cancellationToken); }