In Entity Framework Core, when querying complex object graphs in read-only scenarios, one hidden performance gem is AsNoTrackingWithIdentityResolution()
. It offers the speed benefits of AsNoTracking()
while maintaining consistency by resolving repeated references to the same entity.
But what exactly does this method do, and when should you use it instead of AsNoTracking()
or regular tracking? Let’s dive in.
🧠 What is AsNoTrackingWithIdentityResolution()
?
EF Core uses a Change Tracker to keep track of all loaded entities by default. This is useful for updates, but can be unnecessary overhead when you're only reading data.
AsNoTracking()
disables tracking, making queries faster and memory-efficient. However, when loading related entities (e.g., via .Include()
), AsNoTracking()
can return multiple instances of the same entity if it's referenced more than once.
That’s where AsNoTrackingWithIdentityResolution()
comes in.
✅ It disables change tracking (like AsNoTracking()
),
✅ But also resolves identity — ensuring only one instance per entity is created, even when referenced multiple times.
🔍 Example
Let’s say we have the following models:
public class Post
{
public int Id { get; set; }
public string Title { get; set; }
public Author Author { get; set; }
}
public class Author
{
public int Id { get; set; }
public string Name { get; set; }
}
Using AsNoTracking()
:
var posts = await _context.Posts
.Include(p => p.Author)
.AsNoTracking()
.ToListAsync();
In this case, if an author has written multiple posts, EF Core may return multiple Author instances with the same data — each one tied to a different Post.
Using AsNoTrackingWithIdentityResolution()
:
var posts = await _context.Posts
.Include(p => p.Author)
.AsNoTrackingWithIdentityResolution()
.ToListAsync();
Now, all posts written by the same author will reference the exact same Author object in memory — without enabling full tracking. Cleaner and more consistent.
📊 When to Use It
Scenario | Recommendation |
---|---|
Simple read-only list (flat entities) | Use AsNoTracking()
|
Complex graphs with reused references | Use AsNoTrackingWithIdentityResolution()
|
You plan to modify and save entities | Don't use either — use default tracking |
💡 Performance Considerations
While AsNoTrackingWithIdentityResolution()
is still faster than full tracking, it is slightly slower than plain AsNoTracking()
, because it requires some internal caching to ensure identity resolution.
Method | Tracking | Identity Resolution | Performance |
---|---|---|---|
Default |
✅ Yes | ✅ Yes | 🚫 Slowest |
AsNoTracking() |
❌ No | ❌ No | ✅ Fastest |
AsNoTrackingWithIdentityResolution() |
❌ No | ✅ Yes | ⚡ In between |
✅ Summary
AsNoTrackingWithIdentityResolution()
strikes a great balance between performance and consistency when reading related data without needing tracking.
Use it when:
- You load complex object graphs
- You don’t plan to update the data
- You want to avoid duplication in memory
Don’t use it if:
- You’re updating entities (use full tracking instead)
- You don’t need related entities or identity resolution (then
AsNoTracking()
is faster)
🧠 Final Thought
Knowing when to use tracking, AsNoTracking()
, or AsNoTrackingWithIdentityResolution()
is key to building fast and reliable EF Core applications. The right choice can save both memory and headaches — especially in high-traffic APIs or data-heavy dashboards.
I'm jangjoo and Happy querying! 🚀
Top comments (0)