using LctMonolith.Database.Data; using LctMonolith.Database.Repositories; using LctMonolith.Models.Database; using Microsoft.EntityFrameworkCore.Storage; using EventLog = LctMonolith.Models.Database.EventLog; namespace LctMonolith.Database.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? _rankMissionRules; private IGenericRepository? _rankSkillRules; private IGenericRepository? _missions; private IGenericRepository? _playerMissions; private IGenericRepository? _missionSkillRewards; private IGenericRepository? _skills; private IGenericRepository? _playerSkills; 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 RankMissionRules => _rankMissionRules ??= new GenericRepository(_ctx); public IGenericRepository RankSkillRules => _rankSkillRules ??= new GenericRepository(_ctx); public IGenericRepository Missions => _missions ??= new GenericRepository(_ctx); public IGenericRepository PlayerMissions => _playerMissions ??= new GenericRepository(_ctx); public IGenericRepository MissionSkillRewards => _missionSkillRewards ??= new GenericRepository(_ctx); public IGenericRepository Skills => _skills ??= new GenericRepository(_ctx); public IGenericRepository PlayerSkills => _playerSkills ??= 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(); } }