using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore.Storage; public class MrnGenerator : IMrnGenerator { private readonly AppDbContext _db; private const string MrnPrefix = "VCR"; private const string SequenceName = "clinical.mrn_sequence"; public MrnGenerator(AppDbContext db) { _db = db; } public async Task GenerateNextMrnAsync() { // Use PostgreSQL sequence for atomic, gap-free numbering var connection = _db.Database.GetDbConnection(); var wasOpen = connection.State == System.Data.ConnectionState.Open; if (!wasOpen) await connection.OpenAsync(); try { using var command = connection.CreateCommand(); command.CommandText = $"SELECT nextval('{SequenceName}')"; // If we're in a transaction, enlist the command if (_db.Database.CurrentTransaction is not null) { command.Transaction = _db.Database.CurrentTransaction.GetDbTransaction(); } var nextVal = (long)(await command.ExecuteScalarAsync())!; return $"{MrnPrefix}-{nextVal:D6}"; } finally { if (!wasOpen) await connection.CloseAsync(); } } }