using Microsoft.EntityFrameworkCore.Storage; using StoreService.Database; using StoreService.Database.Entities; namespace StoreService.Repositories; /// /// Coordinates repository access and database transactions. /// public class UnitOfWork : IUnitOfWork { #region Fields private readonly ApplicationContext _context; private IDbContextTransaction? _transaction; #endregion #region Ctor public UnitOfWork( ApplicationContext context, IGenericRepository storeCategories, IGenericRepository storeItems, IGenericRepository storeDiscounts, IGenericRepository storeDiscountItems, IGenericRepository storeOrders, IGenericRepository storeOrderItems, IGenericRepository storeOrderItemDiscounts) { _context = context; StoreCategories = storeCategories; StoreItems = storeItems; StoreDiscounts = storeDiscounts; StoreDiscountItems = storeDiscountItems; StoreOrders = storeOrders; StoreOrderItems = storeOrderItems; StoreOrderItemDiscounts = storeOrderItemDiscounts; } #endregion #region Repositories public IGenericRepository StoreCategories { get; } public IGenericRepository StoreItems { get; } public IGenericRepository StoreDiscounts { get; } public IGenericRepository StoreDiscountItems { get; } public IGenericRepository StoreOrders { get; } public IGenericRepository StoreOrderItems { get; } public IGenericRepository StoreOrderItemDiscounts { get; } #endregion #region Save public bool SaveChanges() => _context.SaveChanges() > 0; public async Task SaveChangesAsync(CancellationToken ct = default) => (await _context.SaveChangesAsync(ct)) > 0; #endregion #region Transactions public async Task BeginTransactionAsync(CancellationToken ct = default) { if (_transaction != null) throw new InvalidOperationException("Transaction already started"); _transaction = await _context.Database.BeginTransactionAsync(ct); } public async Task CommitTransactionAsync(CancellationToken ct = default) { if (_transaction == null) throw new InvalidOperationException("No transaction started"); try { await _transaction.CommitAsync(ct); } catch { await RollbackTransactionAsync(ct); throw; } finally { await _transaction.DisposeAsync(); _transaction = null; } } public async Task RollbackTransactionAsync(CancellationToken ct = default) { if (_transaction == null) return; await _transaction.RollbackAsync(ct); await _transaction.DisposeAsync(); _transaction = null; } #endregion #region Dispose public void Dispose() => _transaction?.Dispose(); public async ValueTask DisposeAsync() { if (_transaction != null) await _transaction.DisposeAsync(); } #endregion }