64 lines
2.3 KiB
C#
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();
|
|
}
|
|
} |