using LctMonolith.Domain.Entities; using LctMonolith.Infrastructure.Data; using LctMonolith.Infrastructure.Repositories; using Microsoft.EntityFrameworkCore.Storage; namespace LctMonolith.Infrastructure.UnitOfWork; /// /// Unit of Work implementation encapsulating repositories and DB transaction scope. /// public class UnitOfWork : IUnitOfWork, IAsyncDisposable { private readonly AppDbContext _ctx; private IDbContextTransaction? _tx; public UnitOfWork(AppDbContext ctx) { _ctx = ctx; } private IGenericRepository? _users; private IGenericRepository? _ranks; private IGenericRepository? _rankRequiredMissions; private IGenericRepository? _rankRequiredCompetencies; private IGenericRepository? _missions; private IGenericRepository? _userMissions; private IGenericRepository? _missionCompetencyRewards; private IGenericRepository? _missionArtifactRewards; private IGenericRepository? _competencies; private IGenericRepository? _userCompetencies; private IGenericRepository? _artifacts; private IGenericRepository? _userArtifacts; private IGenericRepository? _storeItems; private IGenericRepository? _userInventoryItems; private IGenericRepository? _transactions; private IGenericRepository? _eventLogs; private IGenericRepository? _refreshTokens; private IGenericRepository? _notifications; public IGenericRepository Users => _users ??= new GenericRepository(_ctx); public IGenericRepository Ranks => _ranks ??= new GenericRepository(_ctx); public IGenericRepository RankRequiredMissions => _rankRequiredMissions ??= new GenericRepository(_ctx); public IGenericRepository RankRequiredCompetencies => _rankRequiredCompetencies ??= new GenericRepository(_ctx); public IGenericRepository Missions => _missions ??= new GenericRepository(_ctx); public IGenericRepository UserMissions => _userMissions ??= new GenericRepository(_ctx); public IGenericRepository MissionCompetencyRewards => _missionCompetencyRewards ??= new GenericRepository(_ctx); public IGenericRepository MissionArtifactRewards => _missionArtifactRewards ??= new GenericRepository(_ctx); public IGenericRepository Competencies => _competencies ??= new GenericRepository(_ctx); public IGenericRepository UserCompetencies => _userCompetencies ??= new GenericRepository(_ctx); public IGenericRepository Artifacts => _artifacts ??= new GenericRepository(_ctx); public IGenericRepository UserArtifacts => _userArtifacts ??= new GenericRepository(_ctx); public IGenericRepository StoreItems => _storeItems ??= new GenericRepository(_ctx); public IGenericRepository UserInventoryItems => _userInventoryItems ??= new GenericRepository(_ctx); public IGenericRepository Transactions => _transactions ??= new GenericRepository(_ctx); public IGenericRepository EventLogs => _eventLogs ??= new GenericRepository(_ctx); public IGenericRepository RefreshTokens => _refreshTokens ??= new GenericRepository(_ctx); public IGenericRepository Notifications => _notifications ??= new GenericRepository(_ctx); public Task SaveChangesAsync(CancellationToken ct = default) => _ctx.SaveChangesAsync(ct); public async Task BeginTransactionAsync(CancellationToken ct = default) { if (_tx != null) throw new InvalidOperationException("Transaction already started"); _tx = await _ctx.Database.BeginTransactionAsync(ct); } public async Task CommitAsync(CancellationToken ct = default) { if (_tx == null) return; try { await _ctx.SaveChangesAsync(ct); await _tx.CommitAsync(ct); } catch { await RollbackAsync(ct); throw; } finally { await _tx.DisposeAsync(); _tx = null; } } public async Task RollbackAsync(CancellationToken ct = default) { if (_tx == null) return; await _tx.RollbackAsync(ct); await _tx.DisposeAsync(); _tx = null; } public async ValueTask DisposeAsync() { if (_tx != null) await _tx.DisposeAsync(); } }