Introduction
In this article, we will learn about EF Core Tips to Improve Read Performance with AsNoTracking().
Before we start, please take a look at my last article on Entity Framework.
Now, let's get started.
When working with Entity Framework Core (EF Core), one of the easiest ways to boost performance for read-heavy operations is by using AsNoTracking(). This small change can make a big difference in applications like APIs, dashboards, and reporting systems.
🔍 The Problem: Default Tracking Adds Overhead
By default, EF Core tracks every entity it retrieves. This allows it to:
However, this tracking comes at a cost:
👉 If you're only reading data, this tracking is unnecessary.
✅ The Solution: AsNoTracking()
AsNoTracking() tells EF Core:
“Fetch the data, but don’t track it in the DbContext.”
🧪 Example Scenario
Let's say you're building a Product API that returns a list of active products.
🔴 Without AsNoTracking()
public async Task<List<Product>> GetActiveProducts()
{
return await _context.Products
.Where(p => p.IsActive)
.ToListAsync();
}
Issues
🟢 With AsNoTracking()
public async Task<List<Product>> GetActiveProducts()
{
return await _context.Products
.AsNoTracking()
.Where(p => p.IsActive)
.ToListAsync();
}
✅ Benefits
⚡ Real-World Use Case
Imagine a dashboard showing:
Recent orders
Customer lists
Sales reports
All of these are read-only views.
public async Task<List<OrderDto>> GetRecentOrders()
{
return await _context.Orders
.AsNoTracking()
.OrderByDescending(o => o.CreatedDate)
.Select(o => new OrderDto
{
Id = o.Id,
CustomerName = o.Customer.Name,
TotalAmount = o.TotalAmount
})
.ToListAsync();
}
👉 This avoids tracking thousands of rows unnecessarily and keeps your API responsive.
❗ Important Caveat
Entities retrieved using AsNoTracking() are not tracked, so changes won’t be saved automatically.
❌ This Will NOT Work
var product = await _context.Products
.AsNoTracking()
.FirstAsync(p => p.Id == 1);
product.Price = 100;
await _context.SaveChangesAsync(); // No update!
✅ Correct Approach
_context.Products.Update(product);
await _context.SaveChangesAsync();
—or fetch the entity without AsNoTracking() if you intend to update it.
🆚 When Should You Use It?
✅ Use AsNoTracking() When
❌ Avoid When
You plan to update the entity
You rely on automatic change tracking
Complex graph updates are involved
💡 Pro Tip: Make No-Tracking the Default
If most of your queries are read-only:
optionsBuilder.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
You can still override per query:
context.Products.AsTracking().FirstOrDefaultAsync();
🧠 Advanced: Identity Resolution
AsNoTrackingWithIdentityResolution()
Useful For
Complex joins
Related entity graphs
✅ Summary
AsNoTracking() is a low-effort, high-impact performance optimization.
Ideal for read-only queries and APIs.
Reduces memory usage and execution time.
Avoid using it when updates are required.
🚀 Final Thought
If your application is read-heavy (which most modern apps are), start using AsNoTracking() consistently—it’s one of the simplest ways to scale EF Core efficiently.
Conclusion
In this article, I have tried to cover EF Core Tips to Improve Read Performance with AsNoTracking().