EF Code First Concurrency Control and Transaction Management

Entity Framework Code First provides robust mechanisms for handling concurrent database access and maintaining data consistency through trensactions. This article explores the concurrency control patterns and transaction management capabilities built into Code First.

Concurrency Control

Understanding Lock Strategies

Database concurrency mechanisms generally fall into two categories: pessimistic locking and optimistic locking.

Pessimistic Locking: Similar to check-in/check-out systems in version control software like VSS, where a resource becomes exclusively locked once checked out, preventing other users from making modifications.

Optimistic Locking: Like SVN's approach, where multiple users can modify the same file concurrently. Conflicts are resolved during commit based on version information.

Code First implements optimistic locking by default, allowing multiple concurrent modifications to be detected at save time.

Lock Granularity Levels

Row-Level Concurrency Control

Row-level concurrency uses a timestamp or version field to track modifications. Each entity can have only one row version column. In Code First, the [Timestamp] attribute marks the concurrency control field, which must be of type byte[].

[Timestamp]
public byte[] VersionStamp { get; set; }

}


</div>The following example demonstrates row-level concurrency behavior:

<div>```
var employee = new Employee
{
    FirstName = "John",
    LastName = "Smith",
    BadgeNumber = 98765432
};

using (var context = new CompanyDbContext())
{
    context.Employees.Add(employee);
    context.SaveChanges();
}

var firstContext = new CompanyDbContext();
var emp1 = firstContext.Employees.FirstOrDefault();
emp1.FirstName = "Johnny";

using (var secondContext = new CompanyDbContext())
{
    var emp2 = secondContext.Employees.FirstOrDefault();
    emp2.LastName = "Anderson";
    secondContext.SaveChanges();
}

try
{
    firstContext.SaveChanges();
    Console.WriteLine("Save completed successfully");
}
catch (DbUpdateConcurrencyException ex)
{
    Console.WriteLine($"{ex.Entries.First().Entity.GetType().Name} save failed - concurrent modification detected");
}
Console.Read();

Column-Level Concurrency Control

For more granular control over specific properties, Code First provides the [ConcurrencyCheck] attribute. This approach monitors changes to individual columns rather than entire rows.

Consider a modified Employee model with column-level concurrency:

[ConcurrencyCheck]
public int BadgeNumber { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public decimal Salary { get; set; }

public byte[] VersionStamp { get; set; }

}


</div>The BadgeNumber field is now designated as an optimistic concurrency column:

<div>```
var employee = new Employee
{
    FirstName = "John",
    LastName = "Smith",
    BadgeNumber = 11111111
};

using (var context = new CompanyDbContext())
{
    context.Employees.Add(employee);
    context.SaveChanges();
}

var firstContext = new CompanyDbContext();
var emp1 = firstContext.Employees.FirstOrDefault();
emp1.BadgeNumber = 22222222;

using (var secondContext = new CompanyDbContext())
{
    var emp2 = secondContext.Employees.FirstOrDefault();
    emp2.BadgeNumber = 33333333;
    secondContext.SaveChanges();
}

try
{
    firstContext.SaveChanges();
    Console.WriteLine("Save completed successfully");
}
catch (DbUpdateConcurrencyException ex)
{
    Console.WriteLine($"{ex.Entries.First().Entity.GetType().Name} save failed - concurrent modification detected");
}
Console.Read();

Transaction Management

Default Transaction Behavior

Entity Framework automatically wraps all Create, Update, and Delete operations within transactions. When the SaveChanges() method is invoked, the transaction is either committed if all operations succeed or rolled back if any failure occurs.

Distributed Transactions

Distributed transactions coordinate operations across multiple DbContext instances or different databases. The TransactionScope class handles this scenario:

using (var transactionScope = new TransactionScope(TransactionScopeOption.Required)) { // Operations across multiple database contexts transactionScope.Complete(); }


</div>Note that distributed transactions require the Windows Distributed Transaction Coordinator (MSDTC) service to be running.

### Transaction Management in EF6 and Later

Starting with Entity Framework 6, the DbContext class provides the `Database.BeginTransaction()` method, offering more control when executing raw SQL commands within transactional boundaries:

<div>```
using (var context = new CompanyDbContext())
{
    using (var transaction = context.Database.BeginTransaction())
    {
        try
        {
            // Execute database operations
            context.SaveChanges();
            
            transaction.Commit();
        }
        catch (Exception ex)
        {
            transaction.Rollback();
            throw;
        }
    }
}

Tags: entity-framework code-first concurrency-control optimistic-locking timestamp

Posted on Mon, 20 Jul 2026 17:48:38 +0000 by jasonbullard