The Entity Framework doesn't support 2nd level caching straight out of the box. The EFCachingProvider project by Jarek Kowalski provides a means to create a wrapper around the provider to support caching, but most of the examples available are using ObjectContext rather than DbContext to create the wrapper. This expects you to have an edmx file for your model
The purpose of this article is to show how you can create a wrapper around DbContext with EntityConfiguration mappings that will support 2nd level caching in your EF applications.
At it's most basic, 2nd level caching is a query cache. The results of SQL commands are stored in the cache, so that the same SQL commands retrieve their data from the Cache rather than executing the query again against the underlying provider. This can have a performance boost for your application and results in less activity against your database, at the cost of increased memory.
There are some arguments around where caching should occurr when using an ORM. Is it the job of your ORM to cache data, or should that only concern itself with data tasks and caching should be entirely your responsibility within your application domain? Personally, I like to be given the choice - something NHibernate and other ORM's allow you to do by specificying your own cache implementation.
Another problem with Entity Framework caching is that you cannot cache the results of your queries directly since they will be associated with a Context and objects cannot be associated with more than one Context at a time, you will see exceptions such as "An object with the same key already exists in the
ObjectStateManager cannot track multiple objects with the same key"
This normally results in the developer creating 'cachable DTOs' and then translating entity POCO objects into these so they can cache the data. (Further information on this is available here). You then have to implement cache invalidation to make sure your cached objects are kept in sync with any data updates. This certainly adds a layer of complexity within an application that could be taken care of within the ORM.
For more information on second level caching, a very good article by Ayende Rahien can be found here
To keep the download size small, I've only included the very minimum requirements to get the project running. I suggest you use NuGet to refresh the references yourself.
- I have included slightly modified binaries of the EFCachingProvider project, but you can download these yourself. I will describe the changes I have made further in the article.
- The demo application is using NuGet Package EntityFramework.5.0.0-rc
- The application also uses Castle Windsor for some basic dependency injection
The demo application is using SQL Server and everyones favourite database Northwind " /> If you don't have a copy of Northwind, you can download the SQL to create the database from Codeplex
Northwind Database Download
Using the code
First things first, amend the Web.Config file and change the connection string to a valid Northwind connection for your environment.
When you are in the config file, notice that we need to register our custom data providers in the config,
<add name="EF Caching Data Provider" invariant="EFCachingProvider" description="Caching Provider Wrapper" type="EFCachingProvider.EFCachingProviderFactory, EFCachingProvider" />
<add name="EF Tracing Data Provider" invariant="EFTracingProvider" description="Tracing Provider Wrapper" type="EFTracingProvider.EFTracingProviderFactory, EFTracingProvider" />
<add name="EF Generic Provider Wrapper" invariant="EFProviderWrapper" description="Generic Provider Wrapper" type="EFProviderWrapperToolkit.EFProviderWrapperFactory, EFProviderWrapperToolkit" />
When the Entity Framework attempts to create a DbContext, it uses a factory pattern to generate a
DbConnection object. The factory can be set programmatically by using Database.DefaultConnectionFactory or you can specify in web.config. We just need to tell the framework to use our custom factory when creating instances of our context.
<defaultConnectionFactory type="SecondLevelCaching.Data.CachedContextConnectionFactory, SecondLevelCaching.Data">
<context type="SecondLevelCaching.Data.Models.NorthwindContext, SecondLevelCaching.Data">
Connection factories must implement
System.Data.Entity.Infrastructure.IDbConnectionFactory. Our custom implementation is simple for this example, we simply want to create and return a
DbConnection using the
public class CachedContextConnectionFactory : System.Data.Entity.Infrastructure.IDbConnectionFactory
public DbConnection CreateConnection(string nameOrConnectionString)
var providerInvariantName = "System.Data.SqlClient";
var wrappedConnectionString = "wrappedProvider=" +
providerInvariantName + ";" +
return new EFCachingConnection
ConnectionString = wrappedConnectionString,
CachingPolicy = CachingPolicy.CacheAll,
Cache = EntityCache.Instance
The Cache Object
Data contexts are short lived, within web applications they will be created for the lifetime of each HttpRequest. However, we need our caching mechanism to live beyond that so that subsequent HTTP requests can access previously cached data. I'm using a simple Singleton object that is implemented in the
EFCachingConnection requires you set an object that implements
ICache, in a real application you would certainly use
ICache rather than the concrete implementation here. I am only using
InMemoryCache for demonstration purposes to access Cache statistics within the UI.
public class EntityCache
private static InMemoryCache cacheInstance;
private static object lockObject = new object();
public static InMemoryCache Instance
if (cacheInstance == null)
if (cacheInstance == null)
cacheInstance = new InMemoryCache();
Simplify the DbContext
It's always a good idea to create an interface for our DbContext, which we can then use for dependency injection. The interface and implementation look like this.
public interface IDbContext
IQueryable<T> Table<T>() where T : class;
public class NorthwindContext : DbContext, IDbContext
public NorthwindContext(string nameOrConnectionString)
protected override void OnModelCreating(DbModelBuilder modelBuilder)
System.Type configType = typeof(CategoryMap);
var typesToRegister = Assembly.GetAssembly(configType).GetTypes()
.Where(type => !String.IsNullOrEmpty(type.Namespace))
.Where(type => type.BaseType != null && type.BaseType.IsGenericType && type.BaseType.GetGenericTypeDefinition() == typeof(EntityTypeConfiguration<>));
foreach (var type in typesToRegister)
dynamic configurationInstance = Activator.CreateInstance(type);
public IQueryable<T> Table<T>() where T : class
The above simply adds all of the Mapping classes in the OnModelCreating event and provides access to a Queryable source via the Table method.
Wiring it all together
Now we're ready to wire up our dependencies and see it in action. This example is using Windsor Castle but it will work with whatever your DI library of choice is. We only have one interface to tell the container about -
var connectionString = System.Configuration.ConfigurationManager.ConnectionStrings["Northwind"].ConnectionString;
throw new Exception("The connection string for Northwind could not be found in the configuration, please make sure you have set this");
Our HomeController can now resolve this dependency and use it to query the database.
public class HomeController : Controller
private readonly IDbContext dataContext;
public HomeController(IDbContext context)
this.dataContext = context;
The Home View
There's only a single view in this demo, which is a list of customer data from Northwind. Cache statistics are also displayed on the view, will will show you whenever an item has been retrieved from the cache (CacheHit) or retrieved from the database (
CacheAdd). A search box allows you to filter the data by customer name.
Try entering some different search terms. You will notice that you cause the CacheMiss and CacheAdd numbers to increase. Now try entering a search term you have previously used, you should see the CacheHit number increase.
When you see this, you have retrieved your query data from EFCachingProvider and no SQL statement has been run against your database. That's the 2nd level cache in action!
Points of Interest
Some amendments were required to EFCachingProvider to work with Code First. In this project, I used the 'Reverse Engineer Code First' power tools to create my model from the existing database, but if you wanted to use this in an application where the domain Model exists first, then you would receive an exception when the provider tries to create a Command object. This is because in class DbConnectionWrapper, the method CreateDbCommand throws a 'Not Supported' exception. A simple fix to this is to implement the method...
protected override DbCommand CreateDbCommand()
This demo project shows how you can use the Database Connection Factory to provide a custom factory that injects a caching connection into the DbContext pipeline.
For more information on the Caching solution, visit the Codeplex pages linked in the opening paragraph.
06/08/2012: Initial version.