Second Level Cache Beta for EF 6.1 Available

It took a bit longer than I expected but the Beta version of the Second Level Cache for EF 6.1 is now available on NuGet with the source available on Codeplex.

What’s new in the beta version.

  • Support for .NET Framework 4 – the NuGet package now contains two versions of the second level cache assembly – one that is specific to .NET Framework 4 and one that is specific to .NET Framework 4.5. As a result it is now possible to use second level caching in EF 6.1 applications that target .NET Framework 4. (A side note: you should update NuGet packages if you change the .NET Framework version your application targets to avoid errors where (some of) the referenced assemblies target a different version of .NET Framework than the app itself).
  • Support for async (.NET Framework 4.5 only) – results for queries executed asynchronously are now cached.
  • The CachingPolicy and the DefaultCachingPolicy classes merged
  • The CachingPolicy.CanBeCached method was modified to take the Sql query and parameters. This enables more granular control over the cached results. Note that this is a breaking change from alpha release and you will need to update your code if you created a custom CachingPolicy derived class
  • A new mechanisms allowing excluding caching results for specific queries.

Let’s take a closer look at the last two items. They allow achieving a similar goal but in different ways. Starting from the Beta version the SQL query and query parameters are passed to the CanBeCached method in addition to the store entity sets (which are abstractions of database tables). This allows for inspecting the query and its parameters to decide whether the results yielded by the query should be cached. “Inspecting the query and its parameters” may sound easy but the queries generated by EF tend to be complicated and parsing them may not be trivial. Easier cases are where you just have some queries you never want to cache the results for and instead of “inspecting” you just need to compare if the input query is one of these non-cacheable queries
and if it is return false from the method.
(Side note: I personally believe that with regards to caching you are most often interested in tables the results come from and not in what the query does. In this scenario the affectedEntitySets might be more helpful because you can get the names of the tables used in the query without having to try to actually reverse engineer the query. You can get the names of the tables used in the query as follows:

affectedEntitySets.Select(e => e.Table ?? e.Name);

).
Another way to prevent results for a specific query from being cached is to use the new built-in mechanism which for blacklisting queries. This mechanism consists of two parts – a registrar that contains a list of blacklisted queries (i.e. queries whose results won’t be cached) and the DbQuery.NotCached() (and ObjectQuery.NotCached()) extension methods which make using the registrar easier. As a result blacklisting a query is as easy as appending .NotCached() to the query, just like this:

var q = ctx.Entities.Where(e => e.Flag != null).OrderBy(e => e.Id).NotCached();

Blacklisted queries take precedence (i.e. win) over caching policy and therefore the CachingPolicy.CanBeCached() method will never be called for blacklisted queries.
The registrar itself is public and implements the singleton pattern. You can get the instance using the BlacklistedQueriesRegistrar.Instance property and then you will be able to register (or unregister) blacklisted queries manually (note however that queries are compared using string comparison and therefore the registered query must exactly match the query EF would produce – the extension methods ensure the queries are identical by calling .ToString()/.ToTraceString() on the DbQuery/ObjectQuery instance).
As you can see both CachingPolicy.CanBeCached() and the built-in query blacklisting mechanism allow to prevent results for specific queries from being cached. The difference is that the built-in mechanism is very simple to use but does not give the flexibility and granularity offered by the CachingPolicy.CanBeCached() method. On the other hand the flexibility and granularity of the CachingPolicy.CanBeCached() method is not for free – you need to implement at least some logic yourself.

The road to “RTM”.
I consider the Beta version to be feature complete. I am planning to let it bake for a few weeks, fix reported issues and then release the final version. Your part is to try out the Beta version (or upgrade your projects) and report bugs.

2 thoughts on “Second Level Cache Beta for EF 6.1 Available

Leave a comment