using Microsoft.EntityFrameworkCore.Storage; namespace Fitness_core_BE.Infra.UoW { public class EFUnitOfWork : IUnitOfWork { // Central and tenant are separate physical connections -- each gets its own local // transaction. There is no distributed-transaction coordinator wired up, so if one // side's commit fails after the other has already committed, that is NOT rolled back // atomically; true cross-DB atomicity is deferred to a saga/compensating-action // pattern (see the migration plan's Phase 2 step 8). Both sides are always // begun/committed/rolled-back together so ordinary success/failure flows (the vast // majority of call sites) still behave exactly as the single-context version did. private readonly CentralDbContext _central; private readonly TenantDbContext _tenant; private IDbContextTransaction? _centralTransaction; private IDbContextTransaction? _tenantTransaction; public EFUnitOfWork(CentralDbContext central, TenantDbContext tenant) { _central = central; _tenant = tenant; } public async Task BeginAsync(CancellationToken ct = default) { if (_centralTransaction == null) _centralTransaction = await _central.Database.BeginTransactionAsync(ct); if (_tenantTransaction == null) _tenantTransaction = await _tenant.Database.BeginTransactionAsync(ct); } public async Task SaveChangesAsync(CancellationToken ct = default) { await _central.SaveChangesAsync(ct); await _tenant.SaveChangesAsync(ct); } public async Task CommitAsync(CancellationToken ct = default) { await _central.SaveChangesAsync(ct); await _tenant.SaveChangesAsync(ct); if (_centralTransaction != null) { await _centralTransaction.CommitAsync(ct); await _centralTransaction.DisposeAsync(); _centralTransaction = null; } if (_tenantTransaction != null) { await _tenantTransaction.CommitAsync(ct); await _tenantTransaction.DisposeAsync(); _tenantTransaction = null; } } public async Task RollbackAsync(CancellationToken ct = default) { if (_centralTransaction != null) { await _centralTransaction.RollbackAsync(ct); await _centralTransaction.DisposeAsync(); _centralTransaction = null; } if (_tenantTransaction != null) { await _tenantTransaction.RollbackAsync(ct); await _tenantTransaction.DisposeAsync(); _tenantTransaction = null; } } } }