perf(adminui): pooled DbContext factory; role-grants reads per-call, not per-circuit
This commit is contained in:
@@ -8,7 +8,18 @@ namespace ZB.MOM.WW.OtOpcUa.Configuration.Services;
|
||||
/// "exactly one of (ClusterId, IsSystemWide)" invariant at the write surface so a
|
||||
/// malformed row can't land in the DB.
|
||||
/// </summary>
|
||||
public sealed class LdapGroupRoleMappingService(OtOpcUaConfigDbContext db) : ILdapGroupRoleMappingService
|
||||
/// <remarks>
|
||||
/// Takes the <see cref="IDbContextFactory{TContext}"/> and creates + disposes one context PER CALL
|
||||
/// rather than holding an injected context for its lifetime. Its consumers are the RoleGrants Blazor
|
||||
/// page (InteractiveServer, so its DI scope is the whole circuit) and <c>AuthEndpoints.LoginAsync</c>;
|
||||
/// an injected context would pin one context — and one pooled connection — for the life of a circuit,
|
||||
/// and would fault outright ("a second operation was started on this context instance") the moment two
|
||||
/// of that page's renders overlapped. The factory is pooled (see
|
||||
/// <c>ServiceCollectionExtensions.AddOtOpcUaConfigDb</c>), so the per-call create is a pool rent, not
|
||||
/// a fresh context build.
|
||||
/// </remarks>
|
||||
public sealed class LdapGroupRoleMappingService(IDbContextFactory<OtOpcUaConfigDbContext> dbFactory)
|
||||
: ILdapGroupRoleMappingService
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<LdapGroupRoleMapping>> GetByGroupsAsync(
|
||||
@@ -18,6 +29,7 @@ public sealed class LdapGroupRoleMappingService(OtOpcUaConfigDbContext db) : ILd
|
||||
var groupSet = ldapGroups.ToList();
|
||||
if (groupSet.Count == 0) return [];
|
||||
|
||||
await using var db = await dbFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
|
||||
return await db.LdapGroupRoleMappings
|
||||
.AsNoTracking()
|
||||
.Where(m => groupSet.Contains(m.LdapGroup))
|
||||
@@ -27,12 +39,15 @@ public sealed class LdapGroupRoleMappingService(OtOpcUaConfigDbContext db) : ILd
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<IReadOnlyList<LdapGroupRoleMapping>> ListAllAsync(CancellationToken cancellationToken)
|
||||
=> await db.LdapGroupRoleMappings
|
||||
{
|
||||
await using var db = await dbFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
|
||||
return await db.LdapGroupRoleMappings
|
||||
.AsNoTracking()
|
||||
.OrderBy(m => m.LdapGroup)
|
||||
.ThenBy(m => m.ClusterId)
|
||||
.ToListAsync(cancellationToken)
|
||||
.ConfigureAwait(false);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task<LdapGroupRoleMapping> CreateAsync(LdapGroupRoleMapping row, CancellationToken cancellationToken)
|
||||
@@ -43,6 +58,7 @@ public sealed class LdapGroupRoleMappingService(OtOpcUaConfigDbContext db) : ILd
|
||||
if (row.Id == Guid.Empty) row.Id = Guid.NewGuid();
|
||||
if (row.CreatedAtUtc == default) row.CreatedAtUtc = DateTime.UtcNow;
|
||||
|
||||
await using var db = await dbFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
|
||||
db.LdapGroupRoleMappings.Add(row);
|
||||
await db.SaveChangesAsync(cancellationToken).ConfigureAwait(false);
|
||||
return row;
|
||||
@@ -51,6 +67,7 @@ public sealed class LdapGroupRoleMappingService(OtOpcUaConfigDbContext db) : ILd
|
||||
/// <inheritdoc />
|
||||
public async Task DeleteAsync(Guid id, CancellationToken cancellationToken)
|
||||
{
|
||||
await using var db = await dbFactory.CreateDbContextAsync(cancellationToken).ConfigureAwait(false);
|
||||
var existing = await db.LdapGroupRoleMappings.FindAsync([id], cancellationToken).ConfigureAwait(false);
|
||||
if (existing is null) return;
|
||||
db.LdapGroupRoleMappings.Remove(existing);
|
||||
|
||||
Reference in New Issue
Block a user