fix: wrap identity permission bindings with execution strategy transactions
This commit is contained in:
@@ -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)
|
||||||
|
|||||||
@@ -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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
Reference in New Issue
Block a user