Chapter 21. NHibernate.Caches

What is NHibernate.Caches?

NHibernate.Caches are add-ins for NHibernate contributed by Kevin Williams (aka k-dub).  A cache is place where entities are kept (at their first loading); once in cache, they can be retrieved without having to query them (again) in the back-end storage. This means that they are faster to (re)load.

An NHibernate session has an internal (first-level) cache where it keeps its entities. There is no sharing between these caches; so a session is destroyed with its cache. NHibernate provides a second-level cache system; it works at the SessionFactory level. So it is shared by all sessions created by the same SessionFactory.

An important point is that the second-level cache does not cache instances of the object type being cached; instead it caches the individual values of the properties of that object. This provides two benefits. One, NHibernate doesn't have to worry that your client code will manipulate the objects in a way that will disrupt the cache. Two, the relationships and associations do not become stale, and are easy to keep up-to-date because they are simply identifiers. The cache is not a tree of objects but rather a map of arrays.

With the session-per-request model, a high number of Session can concurrently access to the same entity without hitting the database each time; hence the performance gain.

These contributions make it possible to use different cache providers for NHibernate:

  • NHibernate.Caches.Prevalence makes it possible to use the underlying Bamboo.Prevalence implementation as cache provider. Open the file Bamboo.Prevalence.license.txt for more information about its license; you can also visit its website.

  • NHibernate.Caches.SysCache makes it possible to use the underlying System.Web.Caching.Cache implementation as cache provider. This means that you can rely on ASP.NET caching feature to understand how it works. For more information, read (on the MSDN): Caching Application Data.

    Note that SysCache should only be used in ASP.NET applications. For more details, see this knowledge base article.

21.1. How to use a cache?

Here are the steps to follow to enable the second-level cache in NHibernate:

  • Choose the cache provider you want to use and copy its assembly in your assemblies directory (NHibernate.Caches.Prevalence.dll or NHibernate.Caches.SysCache.dll).

  • To tell NHibernate which cache provider to use, add in your NHibernate configuration file (can be YourAssembly.exe.config or web.config or a .cfg.xml file):

    <add key="hibernate.cache.provider_class" value="XXX" />(1)
    <add key="expiration" value="120" />(2)
    						

    (1)

    "XXX" can be either "NHibernate.Caches.Prevalence.PrevalenceCacheProvider, NHibernate.Caches.Prevalence" or "NHibernate.Caches.SysCache.SysCacheProvider, NHibernate.Caches.SysCache".

    (2)

    The expiration value is the number of seconds you wish to cache each entry (here two minutes). This example applies to SysCache only.

  • Add <cache usage="read-write|nonstrict-read-write|read-only"/> (just after <class>) in the mapping of the entities you want to cache. It also works for collections (bag, list, map, set, ...).

Be careful.  Caches are never aware of changes made to the persistent store by another process (though they may be configured to regularly expire cached data). As the caches are created at the SessionFactory level, they are destroyed with the SessionFactory instance; so you must keep them alive as long as you need them.

21.2. Prevalence Cache Configuration

There is only one configurable parameter: prevalenceBase. This is the directory on the file system where the Prevalence engine will save data. It can be relative to the current directory or a full path. If the directory doesn't exist, it will be created.

21.3. SysCache Configuration

As SysCache relies on System.Web.Caching.Cache for the underlying implementation, the configuration is based on the available options that make sense for NHibernate to utilize.

  • expiration = number of seconds to wait before expiring each item

  • priority = a numeric cost of expiring each item, where 1 is a low cost, 5 is the highest, and 3 is normal. Only values 1 through 5 are valid.

SysCache has a config file section handler to allow configuring different expirations and priorities for different regions. Here's an example:

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
	<configSections>
		<section name="syscache" type="NHibernate.Caches.SysCache.SysCacheSectionHandler,NHibernate.Caches.SysCache" />
	</configSections>

	<syscache>
		<cache region="foo" expiration="500" priority="4" />
		<cache region="bar" expiration="300" priority="3" />
	</syscache>
</configuration>