FromCache() and LoadIntoCache() without modifying queries.In high-transaction .NET applications, the database is often the primary bottleneck. While Entity Framework (EF) Core is a powerful Object-Relational-Mapping (ORM), it still hits the database for every single query, leading to performance bottlenecks and scalability problems.
Entity Framework Core Caching solves this by introducing an in-memory distributed cache, NCache, between your application and the database. By intercepting LINQ queries, it serves frequently accessed data instantly from the cache, dramatically reducing expensive database trips.
To get started, ensure you have an NCache clustered cache running.
Run the following command in your Package Manager Console. Ensure that you select the version compatible with your .NET release (e.g., .NET 10).
Install-Package EntityFrameworkCore.NCache
In .NET 8 / 10, binary serialization is restricted. Fortunately, NCache supports JSON Serialization out of the box, which is preferred for modern .NET apps. Ensure your entity classes are public and have parameterless constructors.
The integration of NCache with EF Core happens primarily within your DbContext. You must configure NCache as the cache provider during the application startup or context configuration.
Modifying the DbContext
Override the OnConfiguring method in your DbContext to connect to NCache.
using Alachisoft.NCache.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
public class AppDbContext : DbContext
{
private readonly IConfiguration _configuration;
// Inject configuration via constructor
public AppDbContext(DbContextOptions<AppDbContext> options, IConfiguration configuration)
: base(options)
{
_configuration = configuration;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
// 2. Unique Cache ID configured in NCache Manager
string cacheId = _configuration["NCacheSettings:CacheId"];
// 3. Target-typed new expression (C# 9+) - Type is inferred from variable
CacheConnectionOptions ncacheOptions = new()
{
RetryInterval = TimeSpan.FromSeconds(2),
ConnectionRetries = 2
};
// 4. Initialize the NCache provider
// DependencyType.SqlServer ensures cache syncs with SQL DB changes
NCacheConfiguration.Configure(cacheId, DependencyType.SqlServer, ncacheOptions);
base.OnConfiguring(optionsBuilder);
}
}
NCache extends IQueryable with custom methods. This allows you to cache results directly within your LINQ pipeline.
The Cache-Aside Pattern (FromCache)
This is the most common method. It checks the cache first; if data is missing, it fetches from the DB, caches the result, and returns it.
// Standard LINQ query with caching enabled
var activeCustomers = _context.Customers
.Where(c => c.IsActive)
.FromCache(); // Checks cache first, then DB
Population the Cache with Reference Data (LoadIntoCache)
Use this for "Reference Data" (lookup tables, product catalogs). It always fetches from the database and updates the cache, ensuring the cache is fresh.
// Forces a DB trip and updates the cache
var products = _context.Products
.LoadIntoCache();
Cache-Only Queries for Reference Data (FromCacheOnly)
This queries only the cache and not the database. If data is missing, it returns an empty result or throws an exception (configurable). This is ideal for reference data that is read frequently with ultra-fast reads.
var cachedOrders = _context.Orders
.Where(o => o.Region == "US")
.FromCacheOnly();
Deferred Execution (DeferredCount, DeferredFirst)
Standard operators like, .Count() or .FirstOrDefault(), execute immediately, bypassing the cache interceptor. NCache provides "Deferred" alternatives to delay execution until the cache logic is applied.
// INCORRECT: Hits DB immediately
// var count = _context.Customers.Count();
// CORRECT: Defers execution so caching can work
var count = _context.Customers.DeferredCount().FromCache();
You can control expiration and synchronization using the CachingOptions class.
Prevent the cache from growing indefinitely by setting expiration rules so older data is automatically removed from the cache when it expires.
// 1. Target-typed new expression (inferred type)
CachingOptions options = new()
{
StoreAs = StoreAs.SeperateEntities,
Priority = CacheItemPriority.High
};
// 2. Setting Expiration (Best Practice: Use UtcNow for distributed systems)
options.SetAbsoluteExpiration(DateTime.UtcNow.AddMinutes(10));
// 3. Executing the query
var topSellers = _context.Sellers.FromCache(options);
To ensure the cache is never stale, enable CreateDbDependency. This sets up a watcher on the SQL server rows.
var syncOptions = new CachingOptions
{
CreateDbDependency = true // Auto-remove from cache if SQL row changes
};
var specificOrder = _context.Orders
.Where(o => o.Id == 10248)
.FromCache(syncOptions);
FromCache() queries should not show new traces in SQL Profiler.Q: Does Entity Framework Core cache query results by default?
A: No. Entity Framework Core does not cache query results by default, so repeated queries typically hit the database each time unless you add a caching layer.
Q: What is the easiest way to cache LINQ query results with NCache in EF Core?
A: Use NCache EF Core extension methods like FromCache() to enable cache-aside behavior for LINQ queries without rewriting them.
Q: When should I use LoadIntoCache()?
A: Use LoadIntoCache() for reference/lookup data that you want to proactively populate and refresh in the cache, such as catalogs or configuration tables.
Q: Why do I need DeferredCount() or other deferred execution methods?
A: Some operators like Count() can execute immediately and bypass cache interception. NCache provides deferred alternatives (for example DeferredCount()) so the cache logic is applied before execution.
Q: How does NCache keep EF Core cached data consistent with SQL Server?
A: NCache can use SQL Server dependencies to invalidate cached data when underlying rows change, reducing stale data risk.
Q: Does NCache support EF Core on Linux (e.g., in Docker)?
A: Yes, the EntityFrameworkCore.NCache provider is fully compatible with .NET 8/10 on Linux and Windows.
Q: How do I clear the EF Core cache programmatically?
A: You can access the cache handle directly from the context or use tags (Query Identifiers) to remove groups of data.
_context.GetCache().Remove(entity);
Q: Can I cache complex joins?
A: Yes. FromCache() caches the final result set of the LINQ query. However, ensure the resulting objects are serializable.
Configuring Entity Framework caching in .NET 8 and 10 is straightforward with NCache. By adding a simple FromCache() extension method, you can offload reads from your database and achieve sub-millisecond response times.
Install the EntityFrameworkCore.NCache NuGet package in your staging environment and measure the performance difference on your heaviest read queries.
© Copyright Alachisoft 2002 - . All rights reserved. NCache is a registered trademark of Diyatech Corp.