Skip to main content

How to See What EF Core Will Save with ChangeTracker.DebugView

· 4 min read
Jagdish Kumawat
Founder @ Dewiride

When SaveChangesAsync does something you didn't expect, or nothing at all, you need to see what EF Core thinks has changed. ChangeTracker.DebugView.LongView prints it: every tracked entity, its state, each property's value, and what changed from what. This guide reads it for a real change.

Prerequisites​

  • A .NET C# project with EF Core. The examples use EF Core 10, Oracle's MySql.EntityFrameworkCore, MySQL 9.7, and a products table.

Step 1: Print It​

DebugView is a property on the change tracker. EF Core's debug views page says it "provides a human-readable view of all entities being tracked". This endpoint prints it twice, before and after changing one property:

A temporary endpoint
app.MapPost("/demo/debugview/{id:int}", async (int id, InventoryDbContext db) =>
{
var product = await db.Products.FirstAsync(p => p.Id == id);
var before = db.ChangeTracker.DebugView.LongView;

product.ReorderLevel += 1;
db.ChangeTracker.DetectChanges();
var after = db.ChangeTracker.DebugView.LongView;

var saved = await db.SaveChangesAsync();
return Results.Text($"BEFORE\n{before}\nAFTER\n{after}\nSAVED {saved}\n");
});

DetectChanges() makes EF Core compare the objects with their original values now. SaveChangesAsync does this by itself, so you only need it to see the state before saving.

Step 2: Read the Output​

Response
BEFORE
Product {Id: 3} Unchanged
Id: 3 PK
ArchivedAtUtc: <null>
CategoryId: 1 FK
CreatedAtUtc: '04/11/2026 11:42:47 AM'
Description: <null>
IsArchived: 'False'
Name: 'HDMI cable, 2 m'
QuantityOnHand: 0
ReorderLevel: 5
Sku: 'CBL-HDMI-2M'
UnitPrice: 12.25
UpdatedAtUtc: '04/11/2026 11:42:47 AM'
Version: 0
Category: <null>

AFTER
Product {Id: 3} Modified
Id: 3 PK
ArchivedAtUtc: <null>
CategoryId: 1 FK
CreatedAtUtc: '04/11/2026 11:42:47 AM'
Description: <null>
IsArchived: 'False'
Name: 'HDMI cable, 2 m'
QuantityOnHand: 0
ReorderLevel: 6 Modified Originally 5
Sku: 'CBL-HDMI-2M'
UnitPrice: 12.25
UpdatedAtUtc: '04/11/2026 11:42:47 AM'
Version: 0
Category: <null>

SAVED 1

A terminal with the debug view of a product before and after a change: the first line says Unchanged then Modified, and the ReorderLevel line says 6 Modified Originally 5.

Line by line:

  • Product {Id: 3} Unchanged is the entity, its key and its state. After the change, it says Modified.
  • Id: 3 PK, CategoryId: 1 FK mark the primary and foreign keys.
  • ReorderLevel: 6 Modified Originally 5 is the line you came for: the property's new value, and what it was.
  • Category: <null> is the navigation. It wasn't loaded.
  • SAVED 1 at the end is what SaveChangesAsync returned: one row.

The UPDATE that followed set only what's marked Modified:

API log
info: Microsoft.EntityFrameworkCore.Database.Command[20101]
Executed DbCommand (5ms) [Parameters=[@p1='?' (DbType = Int32), @p0='?' (DbType = Int32), @p2='?' (DbType = Int32)], CommandType='Text', CommandTimeout='30']
UPDATE `products` SET `ReorderLevel` = @p0
WHERE `Id` = @p1 AND `Version` = @p2;
SELECT ROW_COUNT();

Use It to Debug​

What you seeWhat it means
The entity isn't listedIt isn't tracked, for example it came from AsNoTracking or Select, so saving won't touch it
State Unchanged after you changed itThe value is the same as before, so there's nothing to save
State Added for a row that existsYou called Add on an existing object
State Modified on every propertySomeone called Update, which marks them all

For a quick look in the debugger, there's also ShortView, with one line per entity. Don't leave either in production code: they're for debugging.

Common Mistakes​

MistakeWhat happensDo this instead
Reading LongView without DetectChangesChanges you made may not be marked yetCall DetectChanges first
Returning it from a real endpointIt exposes your dataUse it in development only
Logging it in productionIt has every value of every tracked entityKeep it out of production logs

FAQ​

Does reading DebugView change anything?​

No. It only reports. DetectChanges updates the tracker's own state, which SaveChangesAsync would have done anyway.

Where do I see it without changing code?​

In a debugger, expand db.ChangeTracker.DebugView and read LongView.

Conclusion​

db.ChangeTracker.DebugView.LongView lists every tracked entity, its state, and each property, with Modified Originally … on what changed. Call DetectChanges() first, read it when SaveChangesAsync surprises you, and keep it out of production.

Additional Resources​

Stay Updated

Subscribe to our newsletter for the latest tutorials, tech insights, and developer news.

By subscribing, you agree to our privacy policy. Unsubscribe at any time.