Tutorials Entity Framework Core Mastery
The ChangeTracker and Entity States
On this page
The ChangeTracker and Entity States
The ChangeTracker is the internal brain of Entity Framework Core. When you call SaveChanges(), EF Core doesn't inspect the database; it inspects the ChangeTracker. The tracker assigns a specific EntityState (Added, Modified, Deleted, Unchanged, Detached) to every object it manages.
1. Understanding the 5 Entity States
The SQL that gets generated is 100% determined by the object's current state.
| EntityState | When it happens | SaveChanges Output |
|---|---|---|
Detached | The object was created locally, or queried with AsNoTracking. | Ignored. No SQL executed. |
Unchanged | The object was queried, but no C# properties were altered. | Ignored. No SQL executed. |
Added | You called _context.Add(). | INSERT INTO statement. |
Modified | You altered a property, or called _context.Update(). | UPDATE statement. |
Deleted | You called _context.Remove(). | DELETE FROM statement. |
2. Inspecting the Tracker Manually
You can debug exactly what EF Core is planning to do by looking directly into the ChangeTracker.
var user = await _context.Users.FindAsync(1); // State = Unchanged
user.Name = "Sandeep"; // State instantly becomes 'Modified'
// Manually verify the state:
var trackingInfo = _context.Entry(user);
Console.WriteLine(trackingInfo.State); // Prints: Modified
// See exactly WHICH properties changed!
var nameProp = trackingInfo.Property(u => u.Name);
Console.WriteLine($"Original: {nameProp.OriginalValue}, Current: {nameProp.CurrentValue}");
3. Forcing State Changes
You don't have to rely on automatic tracking. You can forcefully dictate the state of an object to bypass EF Core's built-in change detection.
var user = new User { Id = 1, Name = "Force Update" };
// Attach the object and violently FORCE its state to Modified
_context.Entry(user).State = EntityState.Modified;
// Generates an UPDATE statement for ALL columns, because it assumes the whole object is altered
await _context.SaveChangesAsync();
4. Interview Mastery
Q: "We queried a User object. We need to update their `DateOfBirth`, but we DO NOT want to update their `PasswordHash`, even though a rogue developer might accidentally alter the password property in C#. How do we use the ChangeTracker to lock down specific properties from generating SQL updates?"
Architect Answer: "You can manually manipulate the `IsModified` flag on specific properties within the ChangeTracker. Once the object is tracked, you can write: `_context.Entry(user).Property(u => u.PasswordHash).IsModified = false;`. When you call `SaveChanges()`, EF Core scans the object. Even if the password property was egregiously mutated in C# memory, EF Core will explicitly ignore it because you overrode the tracker string. The generated SQL `UPDATE` statement will completely omit the `PasswordHash` column, guaranteeing data integrity at the framework level."