Blog Post

Introducing the NHibernate Couchbase 2nd Level Cache Provider

John Zablocki Published

NHibernate has long supported the notion of a 2nd level caches, where query results are saved to an out-of-process cache for faster retrieval.  The NHContrib project owns these caches, which include ASP.NET HttpCache, Velocity (AppFabric) and Memcached.  That last cache - Memcached - is implemented using the Enyim.Caching library upon which the .NET Couchbase Client Library depends.  Given that dependency and the fact that Couchbase is of course Memcached compatible, adding Couchbase to the set of available 2nd level caches for NHibernate seemed natural.

I've just finished porting the NHContrib Memcached provider to Couchbase.  The new Couchbase cache is available on Couchbase Labs at http://github.com/couchbaselabs/nhibernate-caches-couchbase.  It's plug and play and comes with a sample ASP.NET MVC project to demonstrate its usage.  I've detailed setup in the README.md file in the repository, but I'll point out some of the sample project config to give a sense of how to use it.

In the sample, I use FluentNHibernate for configuration.  I won't describe FluentNHibernate here other than to say it allows you to configure NHibernate in code, instead of the standard set of XML files.  In the sample project, I have a static class with a static method for configuring the client.

public class FluentSession
{
    public static ISessionFactory CreateSessionFactory()
    {
        string connectionString = @"Data Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|Beers.mdf;Integrated Security=True;User Instance=True";

        return Fluently.Configure()
            .Database(MsSqlConfiguration.MsSql2008.ConnectionString(connectionString))
            <strong>.Cache(c => c.UseQueryCache().ProviderClass<CouchbaseCacheProvider>())</strong>
            .Mappings(m =>m.FluentMappings.AddFromAssemblyOf<Beer>())
            .ExposeConfiguration(c => c.SetProperty("current_session_context_class", "web"))
            .BuildSessionFactory();
    }

    ...
}

The line relevant to the Couchbase cache provider is in the fluent .Cache call where, you're instructing NHibernate to cache queries and to cache them by using the new Couchbase caching provider.  Beyond that, there's nothing specific about the Couchbase provider that needs to be configured.  However, there are some other pieces necessary for using any 2nd level cache.  You need to enable caching on the model class.

So for my beer class:

public class Beer
{
    [Required]
    public virtual int Id { get; set; }

    [Required]
    public virtual string Name { get; set; }

    [Required]
    public virtual string Brewery { get; set; }

    [Required]
    public virtual float ABV { get; set; }
}

I have to set the Cache option in the BeerMap.

public class BeerMap : ClassMap<Beer>
{
    public BeerMap()
    {
        Table("Beers");
<strong>        Cache.ReadWrite();

</strong>        Id(b => b.Id);
        Map(b => b.Name).Not.Nullable().Length(30);
        Map(b => b.Brewery).Not.Nullable().Length(50);
        Map(b => b.ABV).Not.Nullable();
    }
}

Something to keep in mind with any 2nd level cache and web projects.  By default cache will be per request - not session.  You need to configure an ASP.NET application to manage your sessions as described here.  If you don't configure your app in this way, you'll find that the cache is being recreated for every request- even within the same session.  

So if you've been waiting for a wicked fast and wicked scalable 2nd level caching solution for NHibernate, it's here.

Please note that this provider is included as part of Couchbase Labs and is not an officially supported product.  You're free to use the code however you'd like as it's licensed under Apache License 2.0.  The original project found in NHContrib is licensed under the LGPL.