Files
amrez-nova-eop-services-api/AMREZ.EOP.Infrastructures/Storage/DbScope.cs
Thanakarn Klangkasame 92e614674c Init Git
2025-09-30 11:01:02 +07:00

64 lines
2.3 KiB
C#

using System.Collections.Concurrent;
using AMREZ.EOP.Abstractions.Applications.Tenancy;
using AMREZ.EOP.Abstractions.Storage;
using AMREZ.EOP.Infrastructures.Data;
using AMREZ.EOP.Infrastructures.Options;
using Microsoft.Extensions.Options;
using StackExchange.Redis;
using IDatabase = Microsoft.EntityFrameworkCore.Storage.IDatabase;
namespace AMREZ.EOP.Infrastructures.Storage;
public sealed class DbScope : IDbScope, IAsyncDisposable
{
private readonly ITenantDbContextFactory _factory;
private readonly IOptions<AuthOptions> _opts;
private readonly IConnectionMultiplexer? _redis;
private readonly ConcurrentDictionary<Type, object> _cache = new();
public DbScope(ITenantDbContextFactory factory, IOptions<AuthOptions> opts, IConnectionMultiplexer? redis = null)
{ _factory = factory; _opts = opts; _redis = redis; }
private ITenantContext? _tenant;
public void EnsureForTenant(ITenantContext tenant)
{
if (_tenant?.Id == tenant.Id) return;
_tenant = tenant;
_cache.Clear();
var ef = _factory.Create<AppDbContext>(tenant);
_cache[typeof(AppDbContext)] = ef;
if (_redis != null)
_cache[typeof(IDatabase)] = _redis.GetDatabase(_opts.Value.RedisDb);
}
public TContext Get<TContext>() where TContext : class
{
if (_tenant is null) throw new InvalidOperationException("Tenant not set. Call EnsureForTenant first.");
if (_cache.TryGetValue(typeof(TContext), out var obj)) return (TContext)obj;
if (typeof(TContext) == typeof(AppDbContext))
{
var ef = _factory.Create<AppDbContext>(_tenant);
_cache[typeof(AppDbContext)] = ef;
return (TContext)(object)ef;
}
if (typeof(TContext) == typeof(IDatabase))
{
if (_redis is null) throw new InvalidOperationException("Redis not configured");
var db = _redis.GetDatabase(_opts.Value.RedisDb);
_cache[typeof(IDatabase)] = db;
return (TContext)(object)db;
}
throw new NotSupportedException($"Unknown context type {typeof(TContext).Name}");
}
public async ValueTask DisposeAsync()
{
if (_cache.TryGetValue(typeof(AppDbContext), out var ef) && ef is AppDbContext db)
await db.DisposeAsync();
_cache.Clear();
}
}