The Entity Framework doesn't support second 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
EntityConfiguration mappings that will support second level caching in your EF applications.
At its most basic, second 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 occur 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 ORMs allow you to do by specifying 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
- The application also uses Castle Windsor for some basic dependency injection.
The demo application uses SQL Server and everyone's favourite database
Northwind . If you don't have a copy of
Northwind, you can download the SQL to create the database from Codeplex.
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.
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 :
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 to 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 looks 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
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
throw new Exception("The connection string for Northwind
could not be found in the configuration, please make sure you have set this");
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, which 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
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 second level cache in action!
Points of Interest
Some amendments were required for
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
For more information on the Caching solution, visit the Codeplex pages linked in the opening paragraph.
- 6th August, 2012: Initial version
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.