87 lines
3.6 KiB
C#
87 lines
3.6 KiB
C#
using Microsoft.EntityFrameworkCore;
|
|
using TakeoutSaaS.Domain.Identity.Entities;
|
|
using TakeoutSaaS.Domain.Identity.Repositories;
|
|
|
|
namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
|
|
|
|
/// <summary>
|
|
/// EF 用户-角色仓储。
|
|
/// </summary>
|
|
public sealed class EfUserRoleRepository(IdentityDbContext dbContext) : IUserRoleRepository
|
|
{
|
|
/// <summary>
|
|
/// 根据用户 ID 集合获取用户角色映射。
|
|
/// </summary>
|
|
/// <param name="tenantId">租户 ID。</param>
|
|
/// <param name="userIds">用户 ID 集合。</param>
|
|
/// <param name="cancellationToken">取消标记。</param>
|
|
/// <returns>用户角色映射列表。</returns>
|
|
public Task<IReadOnlyList<UserRole>> GetByUserIdsAsync(long tenantId, IEnumerable<long> userIds, CancellationToken cancellationToken = default)
|
|
=> dbContext.UserRoles.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && userIds.Contains(x.UserId))
|
|
.ToListAsync(cancellationToken)
|
|
.ContinueWith(t => (IReadOnlyList<UserRole>)t.Result, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 获取指定用户的角色集合。
|
|
/// </summary>
|
|
/// <param name="tenantId">租户 ID。</param>
|
|
/// <param name="userId">用户 ID。</param>
|
|
/// <param name="cancellationToken">取消标记。</param>
|
|
/// <returns>用户角色列表。</returns>
|
|
public Task<IReadOnlyList<UserRole>> GetByUserIdAsync(long tenantId, long userId, CancellationToken cancellationToken = default)
|
|
=> dbContext.UserRoles.AsNoTracking()
|
|
.Where(x => x.TenantId == tenantId && x.UserId == userId)
|
|
.ToListAsync(cancellationToken)
|
|
.ContinueWith(t => (IReadOnlyList<UserRole>)t.Result, cancellationToken);
|
|
|
|
/// <summary>
|
|
/// 替换指定用户的角色集合。
|
|
/// </summary>
|
|
/// <param name="tenantId">租户 ID。</param>
|
|
/// <param name="userId">用户 ID。</param>
|
|
/// <param name="roleIds">角色 ID 集合。</param>
|
|
/// <param name="cancellationToken">取消标记。</param>
|
|
/// <returns>异步任务。</returns>
|
|
public async Task ReplaceUserRolesAsync(long tenantId, long userId, IEnumerable<long> 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);
|
|
});
|
|
}
|
|
|
|
/// <summary>
|
|
/// 保存仓储变更。
|
|
/// </summary>
|
|
/// <param name="cancellationToken">取消标记。</param>
|
|
/// <returns>保存任务。</returns>
|
|
public Task SaveChangesAsync(CancellationToken cancellationToken = default)
|
|
=> dbContext.SaveChangesAsync(cancellationToken);
|
|
}
|