EF Core Change Tracking

Entity Framework Core (EF Core) provides a powerful mechanism for tracking changes made to entities in your application. This change tracking is fundamental to how EF Core determines what to update, insert, or delete in the database when you call SaveChanges().

How Change Tracking Works

When EF Core loads entities from the database, it creates a snapshot of their state. As you modify these entities (e.g., update properties, add new ones, remove existing ones), EF Core compares the current state with the original snapshot to detect any differences. This process happens automatically within the DbContext.

The DbContext and Change Tracking

The DbContext instance is the gateway to your data and is responsible for managing the lifecycle of your entities, including change tracking. Each DbContext instance maintains a collection of tracked entities.

Entity States

EF Core assigns a state to each tracked entity. The most common states are:

Manually Managing Change Tracking

While EF Core does a great job of automatically tracking changes, there are scenarios where you might want to interact with the change tracker directly. The DbContext provides properties and methods for this purpose.

Accessing the Change Tracker

You can access the change tracker through the ChangeTracker property of your DbContext:


var entries = context.ChangeTracker.Entries();
foreach (var entry in entries)
{
    Console.WriteLine($"Entity: {entry.Entity.GetType().Name}, State: {entry.State}");
}
            

Marking Entities

You can manually set the state of an entity:


// For a new entity to be added
context.Entry(newProduct).State = EntityState.Added;

// For an existing entity to be marked as modified (if EF Core didn't detect it)
context.Entry(existingProduct).State = EntityState.Modified;

// For an existing entity to be marked as deleted
context.Entry(productToDelete).State = EntityState.Deleted;

// To mark an entity as unchanged
context.Entry(unchangedProduct).State = EntityState.Unchanged;
            
Tip: When you attach a detached entity, EF Core will initially mark it as Unchanged. You then need to explicitly mark it as Added, Modified, or Deleted if you intend to persist those changes.

Detecting Changes

By default, EF Core detects changes to properties when SaveChanges() is called. This is done by comparing the current values with the original values stored when the entity was loaded. If you want to override this behavior or perform more granular change detection, EF Core provides options.

DetectChanges()

You can manually trigger change detection at any time:


context.ChangeTracker.DetectChanges(); // Forces EF Core to check all tracked entities for changes
context.SaveChanges();
            

Sensitive Data Logging

For debugging purposes, EF Core can log sensitive data when changes are detected. This is useful for understanding what has changed but should be used with caution in production environments.

Performance Considerations

Change tracking adds overhead. For high-performance scenarios where you are only reading data or performing bulk operations, consider using:

Example with AsNoTracking()


var products = context.Products.AsNoTracking().ToList();
// Modifications to 'products' will not be tracked by the context.
// Calling context.SaveChanges() would not affect these entities.
            

Conclusion

EF Core's change tracking is a sophisticated feature that simplifies data persistence. Understanding its mechanics, entity states, and how to interact with the change tracker will help you build more robust and efficient data-driven applications.

Last Updated: October 26, 2023