Blog
Mert Özen's blog posts on software development, backend, frontend, and DevOps.
Optimistic Concurrency End to End: From rowversion to ETag, If-Match, 412 and a Conflict UI
Building optimistic concurrency end to end on the web means exposing rowversion as an ETag, requiring If-Match on updates (428 otherwise), returning 412 with the current values on a mismatch and doing a field-level three-way merge on the client. As a follow-up to the EF Core Concurrency post, this post shows the HTTP and Angular side with real output.
Numbering: Invoice and Order Numbers, Gapless Sequences and Yearly Resets
An invoice number that must be consecutive shouldn't come from an identity, MAX + 1 or a SEQUENCE, but from a locked UPDATE on a counter table keyed by (Series, Year) inside the approval transaction; for order numbers where gaps are acceptable, a SEQUENCE is enough. The post shows GİB's 16-character document number format, gapless numbering under 50 concurrent approvals, the effect of lock duration on throughput and yearly resets by invoice date, with real output.
When the Status Column Is Updated from Everywhere: Transition Tables, State Machines and Status History
Stop treating the status column as a field any endpoint can write: let the client send an action instead of a status, keep allowed transitions in one place (a transition table, domain methods or Stateless), write every transition with its reason to a status history in the same transaction, and use a rowversion to stop double approvals.
C# Synchronization: lock, Interlocked, SemaphoreSlim and Concurrent Collections
Why sold++ never reaches a million: race conditions and the check-then-act race. The rules of lock and why you can't await inside it, atomic counters and CompareExchange with Interlocked, the SemaphoreSlim pattern for an async cache, ConcurrentDictionary factories that run more than once and the Lazy<T> fix.
Concurrent Work in C# with Task.WhenAll and Task.WhenAny
Async code is not concurrent by itself: awaiting independent work one by one adds the durations up. Starting first and waiting later, getting ordered results with Task.WhenAll, the trap of starting tasks twice with LINQ Select, WhenAll waiting for everyone after a failure, first answer and timeouts with WhenAny, losers that keep running, and processing tasks as they complete.
Concurrency in EF Core: Tokens, rowversion and DbUpdateConcurrencyException
We reproduce a lost update, set up optimistic concurrency with a concurrency token, use rowversion on SQL Server and a Guid version column on SQLite, and resolve DbUpdateConcurrencyException with a retry loop.