fix: wrap identity permission bindings with execution strategy transactions

This commit is contained in:
2025-12-06 14:35:06 +08:00
parent 4120aec055
commit ab4e407f9c
3 changed files with 75 additions and 58 deletions

View File

@@ -28,25 +28,30 @@ public sealed class EfRolePermissionRepository(IdentityDbContext dbContext) : IR
public async Task ReplaceRolePermissionsAsync(long tenantId, long roleId, IEnumerable<long> permissionIds, CancellationToken cancellationToken = default) public async Task ReplaceRolePermissionsAsync(long tenantId, long roleId, IEnumerable<long> permissionIds, CancellationToken cancellationToken = default)
{ {
await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken); var strategy = dbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
var existing = await dbContext.RolePermissions
.Where(x => x.TenantId == tenantId && x.RoleId == roleId)
.ToListAsync(cancellationToken);
dbContext.RolePermissions.RemoveRange(existing);
await dbContext.SaveChangesAsync(cancellationToken);
var toAdd = permissionIds.Distinct().Select(permissionId => new RolePermission
{ {
TenantId = tenantId, await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken);
RoleId = roleId,
PermissionId = permissionId
});
await dbContext.RolePermissions.AddRangeAsync(toAdd, cancellationToken); var existing = await dbContext.RolePermissions
await dbContext.SaveChangesAsync(cancellationToken); .Where(x => x.TenantId == tenantId && x.RoleId == roleId)
await trx.CommitAsync(cancellationToken); .ToListAsync(cancellationToken);
dbContext.RolePermissions.RemoveRange(existing);
await dbContext.SaveChangesAsync(cancellationToken);
var toAdd = permissionIds.Distinct().Select(permissionId => new RolePermission
{
TenantId = tenantId,
RoleId = roleId,
PermissionId = permissionId
});
await dbContext.RolePermissions.AddRangeAsync(toAdd, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
await trx.CommitAsync(cancellationToken);
});
} }
public Task SaveChangesAsync(CancellationToken cancellationToken = default) public Task SaveChangesAsync(CancellationToken cancellationToken = default)

View File

@@ -86,35 +86,42 @@ public sealed class EfRoleTemplateRepository(IdentityDbContext dbContext) : IRol
private async Task ReplacePermissionsInternalAsync(RoleTemplate template, IEnumerable<string> permissionCodes, CancellationToken cancellationToken) private async Task ReplacePermissionsInternalAsync(RoleTemplate template, IEnumerable<string> permissionCodes, CancellationToken cancellationToken)
{ {
await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken); var strategy = dbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
// 确保模板已持久化,便于 FK 正确填充
if (!dbContext.Entry(template).IsKeySet || template.Id == 0)
{ {
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. 清空旧权限
var existing = await dbContext.RoleTemplatePermissions
.Where(x => x.RoleTemplateId == template.Id)
.ToListAsync(cancellationToken);
dbContext.RoleTemplatePermissions.RemoveRange(existing);
await dbContext.SaveChangesAsync(cancellationToken); await dbContext.SaveChangesAsync(cancellationToken);
}
var normalized = permissionCodes // 4. 插入新权限
.Where(code => !string.IsNullOrWhiteSpace(code)) var toAdd = normalized.Select(code => new RoleTemplatePermission
.Select(code => code.Trim()) {
.Distinct(StringComparer.OrdinalIgnoreCase) RoleTemplateId = template.Id,
.ToArray(); PermissionCode = code
});
var existing = await dbContext.RoleTemplatePermissions await dbContext.RoleTemplatePermissions.AddRangeAsync(toAdd, cancellationToken);
.Where(x => x.RoleTemplateId == template.Id) await dbContext.SaveChangesAsync(cancellationToken);
.ToListAsync(cancellationToken);
dbContext.RoleTemplatePermissions.RemoveRange(existing); await trx.CommitAsync(cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
var toAdd = normalized.Select(code => new RoleTemplatePermission
{
RoleTemplateId = template.Id,
PermissionCode = code
}); });
await dbContext.RoleTemplatePermissions.AddRangeAsync(toAdd, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
await trx.CommitAsync(cancellationToken);
} }
} }

View File

@@ -23,25 +23,30 @@ public sealed class EfUserRoleRepository(IdentityDbContext dbContext) : IUserRol
public async Task ReplaceUserRolesAsync(long tenantId, long userId, IEnumerable<long> roleIds, CancellationToken cancellationToken = default) public async Task ReplaceUserRolesAsync(long tenantId, long userId, IEnumerable<long> roleIds, CancellationToken cancellationToken = default)
{ {
await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken); var strategy = dbContext.Database.CreateExecutionStrategy();
await strategy.ExecuteAsync(async () =>
var existing = await dbContext.UserRoles
.Where(x => x.TenantId == tenantId && x.UserId == userId)
.ToListAsync(cancellationToken);
dbContext.UserRoles.RemoveRange(existing);
await dbContext.SaveChangesAsync(cancellationToken);
var toAdd = roleIds.Distinct().Select(roleId => new UserRole
{ {
TenantId = tenantId, await using var trx = await dbContext.Database.BeginTransactionAsync(cancellationToken);
UserId = userId,
RoleId = roleId
});
await dbContext.UserRoles.AddRangeAsync(toAdd, cancellationToken); var existing = await dbContext.UserRoles
await dbContext.SaveChangesAsync(cancellationToken); .Where(x => x.TenantId == tenantId && x.UserId == userId)
await trx.CommitAsync(cancellationToken); .ToListAsync(cancellationToken);
dbContext.UserRoles.RemoveRange(existing);
await dbContext.SaveChangesAsync(cancellationToken);
var toAdd = roleIds.Distinct().Select(roleId => new UserRole
{
TenantId = tenantId,
UserId = userId,
RoleId = roleId
});
await dbContext.UserRoles.AddRangeAsync(toAdd, cancellationToken);
await dbContext.SaveChangesAsync(cancellationToken);
await trx.CommitAsync(cancellationToken);
});
} }
public Task SaveChangesAsync(CancellationToken cancellationToken = default) public Task SaveChangesAsync(CancellationToken cancellationToken = default)