Introduction
In enterprise-grade applications, data consistency and integrity are non-negotiable.
When multiple users or services interact with the same data simultaneously, it’s crucial to manage transactions and handle concurrency conflicts effectively.
With Entity Framework Core 9 (EF Core 9), Microsoft has refined transaction handling and introduced improved features for optimistic concurrency, savepoints, and distributed transactions—making it more powerful for real-world, multi-user systems.
This article explains how to handle transactions and concurrency in EF Core 9, using simple, step-by-step explanations, diagrams, and practical code examples.
1. Understanding Transactions in EF Core
A transaction is a sequence of database operations that must be treated as a single logical unit of work.
If any operation fails, all operations within that transaction should be rolled back to maintain data consistency.
ACID Properties
EF Core transactions follow ACID principles:
Atomicity: All operations complete or none do.
Consistency: The database remains valid after the transaction.
Isolation: One transaction’s changes are invisible to others until committed.
Durability: Once committed, data is permanent even after system failures.
2. Technical Workflow (Flowchart)
+---------------------------+
| Begin Transaction |
+---------------------------+
|
v
+---------------------------+
| Perform DB Operations |
| (Insert, Update, Delete) |
+---------------------------+
|
v
+---------------------------+
| Error Occurred? |
+-------------+-------------+
| Yes
v
+-------------------+
| Rollback Changes |
+-------------------+
|
v
+-------------+-------------+
| No |
v |
+---------------------------+
| Commit Transaction |
+---------------------------+3. Implementing Transactions in EF Core 9
EF Core automatically creates a transaction when SaveChanges() is called.
However, for more control, you can manually manage transactions using BeginTransaction().
Example 1: Manual Transaction Handling
using var transaction = await _context.Database.BeginTransactionAsync();
try
{
var customer = new Customer { Name = "Rajesh", Email = "[email protected]" };
_context.Customers.Add(customer);
await _context.SaveChangesAsync();
var order = new Order { CustomerId = customer.Id, TotalAmount = 2500 };
_context.Orders.Add(order);
await _context.SaveChangesAsync();
await transaction.CommitAsync();
}
catch (Exception)
{
await transaction.RollbackAsync();
throw;
}
Explanation
A transaction is explicitly started using
BeginTransactionAsync().If any operation fails, we rollback to ensure no partial data is saved.
On success,
CommitAsync()finalizes all operations.
4. Nested Transactions with Savepoints
EF Core 9 supports Savepoints, allowing partial rollbacks inside a transaction—useful for complex workflows.
Example 2: Using Savepoints
using var transaction = await _context.Database.BeginTransactionAsync();
try
{
_context.Customers.Add(new Customer { Name = "Amit" });
await _context.SaveChangesAsync();
await transaction.CreateSavepointAsync("BeforeOrder");
_context.Orders.Add(new Order { CustomerId = 1, TotalAmount = 5000 });
await _context.SaveChangesAsync();
// Simulate failure
throw new Exception("Order creation failed!");
await transaction.CommitAsync();
}
catch (Exception)
{
await transaction.RollbackToSavepointAsync("BeforeOrder");
await transaction.CommitAsync();
}
Key Takeaway
Savepoints help preserve partial progress and rollback specific sections without discarding the entire transaction.
5. Distributed Transactions
When multiple databases or microservices are involved, EF Core 9 supports distributed transactions through TransactionScope.
Example 3: Using TransactionScope

Join the conversation! Your thoughts help the community grow.