Learn / .NET API Engineering Path
EF Core Write Transactions and Concurrency
Make write paths safe under retries, concurrency conflicts, and partial failures with explicit transaction boundaries.
Course: .NET API Engineering Path. Level: Advanced. Topic: Typed backend.
Stage: advanced - Advanced data access - Write safety, transactions, and concurrency. Treat writes as production workflows with transaction ownership, idempotency, and explicit conflict behavior.
Outcomes
- Wrap multi-step writes in clear transactions.
- Handle optimistic concurrency conflicts.
- Keep idempotency decisions visible in review.
Concepts
- transaction
- row version
- idempotency key
- SaveChangesAsync
Concept flow
Show how write safety, transactions, and concurrency moves from trigger to implementation outcome in .NET APIs.
- Endpoint
- Command handler
- Transaction
- DbContext
- Outbox
- Conflict response
Session flow
- Model transaction (concept, 11 min) — Name the decisions behind transaction before writing code.
- Wrap multi-step writes in clear transactions.
- Explain where transaction belongs in order management API.
- Build the vertical slice (walkthrough, 19 min) — Implement the smallest useful slice in Orders/ConfirmOrderHandler.cs.
- Handle optimistic concurrency conflicts.
- Connect row version to a working example.
- Verify and harden (exercise, 13 min) — Write a test for stale updates.
- Keep idempotency decisions visible in review.
- Record one risk or follow-up before moving on.
Code example
C# in Orders/ConfirmOrderHandler.cs.
public async Task<Results<NoContent, Conflict>> ConfirmAsync(Guid id, byte[] version, CancellationToken ct)
{
var order = await db.Orders.SingleOrDefaultAsync(item => item.Id == id, ct);
if (order is null) return TypedResults.Conflict();
db.Entry(order).Property("RowVersion").OriginalValue = version;
order.Confirm();
try
{
await db.SaveChangesAsync(ct);
return TypedResults.NoContent();
}
catch (DbUpdateConcurrencyException)
{
return TypedResults.Conflict();
}
}
Walkthrough examples
- EF Core Write Transactions and Concurrency in a order management API — A team is extending a production-grade ASP.NET Core order API and needs this lesson's pattern to be clear enough for review, testing, and future maintenance.
- File: Orders/ConfirmOrderHandler.cs
- File: src/Orders.Application/ef-core-write-transactions-and-concurrency.cs
- File: tests/Orders.Api.Tests/ef-core-write-transactions-and-concurrency.Tests.cs
- File: docs/dotnet-advanced/ef-core-write-transactions-and-concurrency.md
- Start from the provided C# snippet and make the intent visible in names and boundaries.
- Apply the checklist item "Transaction boundary is named" before adding extra behavior.
- Write down how the implementation changes when row version fails or becomes slow.
Practice
- Add a row-version field to one write model.
- Map concurrency failure to a typed conflict response.
- Write a test for stale updates.
Checklist
- Transaction boundary is named
- Concurrency conflict is handled
- Retry/idempotency decision is documented
- Write test covers stale state
Quiz prompts
- What is the most reviewable response to a stale row-version update? — Concurrency conflicts are expected business failures and deserve explicit contract behavior.
- A teammate wants to hide transaction inside a convenient helper. What should you check first? — Place transaction at the boundary that keeps order management API behavior explicit, testable, and reviewable.
- Which artifact best proves this .NET APIs lesson is ready for review? — Production-ready learning needs evidence: a test, trace, command, screenshot, or log that catches the risk again.
- Advanced data access: a teammate says the happy path works, but "Transaction boundaries" is still implicit. What should you ask for before merging? — Transaction boundaries belongs in the advanced stage only when the decision is visible, testable, and tied to a realistic failure mode.
- A reviewer has five minutes to evaluate this advanced .NET APIs slice. Which evidence is strongest? — Upgrade the order write path with a transaction boundary, stale-update conflict handling, and an idempotency decision note.
Flashcards
- Advanced data access: what decision does "Transaction boundaries" force you to make? Name where a multi-step write starts, commits, rolls back, and emits follow-up work. Evidence prompt: Wrap one multi-step order write in a transaction and document what happens after rollback.
- Advanced data access: what decision does "Optimistic concurrency" force you to make? Use row versions or equivalent tokens to detect stale writes without locking every reader. Evidence prompt: Write a stale update test and map the conflict to a typed API response.
- Advanced data access: what decision does "Idempotency review" force you to make? Decide which commands can be retried safely and which need explicit idempotency keys. Evidence prompt: Add an idempotency note for one command and name the duplicate-request behavior.
- In .NET APIs, what should you remember about transaction? transaction matters here because it supports "Wrap multi-step writes in clear transactions.".
- In .NET APIs, what should you remember about row version? row version matters here because it supports "Handle optimistic concurrency conflicts.".
- In .NET APIs, what should you remember about idempotency key? idempotency key matters here because it supports "Keep idempotency decisions visible in review.".
- In .NET APIs, what should you remember about SaveChangesAsync? SaveChangesAsync matters here because it supports "Wrap multi-step writes in clear transactions.".
Labs
- Ship a ef core write transactions and concurrency slice — Extend a production-grade ASP.NET Core order API with a small but reviewable feature that proves the lesson's architecture in code.
- Upgrade the order write path with a transaction boundary, stale-update conflict handling, and an idempotency decision note.
- Wrap one multi-step order write in a transaction and document what happens after rollback.
- Write a stale update test and map the conflict to a typed API response.
- Add an idempotency note for one command and name the duplicate-request behavior.
- Add a row-version field to one write model.
- Map concurrency failure to a typed conflict response.
- The lab demonstrates the advanced data access outcome without skipping earlier contract evidence.
- Each subtopic has a concrete artifact: Transaction boundaries, Optimistic concurrency, Idempotency review.
- The review notes explain how this level changes ownership, verification, or operational risk.
Challenge
- Review-ready ef core write transactions and concurrency (Stretch) — Upgrade the order write path with a transaction boundary, stale-update conflict handling, and an idempotency decision note.
- All checklist items are either implemented or documented with a reason.
- The change can be understood from Orders/ConfirmOrderHandler.cs plus one short note.
- The concept diagram names ownership, failure handling, and verification points.
- A teammate could run the verification steps without asking for hidden context.
Canonical lesson URL