dotNetChris @ Marisic.Net

January 28, 2009

Creating a common generic and extensible NHiberate Repository

In my previous post Conversation Per Business Transaction using PostSharp and IoC I dealt with the session management aspect of NHiberate however by the end of my development of the business conversation aspect I realized that my current data provider scheme created a lot of duplicate code. As we all know any code that is duplicated becomes a nightmare to maintain so I went through and refactored first a truly generic repository.

public interface IRepository<T>
{
    ICriteria GetAll();
    T Get<U>(U id);
    void Save(T obj);
    ICriteria GetRange(int resultSet, int rangeSize);
}

This is a rather basic interface that will handle the most common operations to my data providers, currently it can handle getting all of the items in my database for a type, a page collection into the list of items in my database, get a specific item and save a new item (or update an existing item). The only minorly unsightly part is the Get<U> method this just allows passing any type of ID instead of declaring it as int statically.

On to implementing the interface:

public class Repository<T> : IRepository<T>
{
    private readonly IConversation _conversation;

    public Repository(IConversation conversation)
    {
        _conversation = conversation;
    }

    #region IRepository<T> Members

    ICriteria IRepository<T>.GetAll()
    {
        return _conversation.Session.CreateCriteria(typeof (T))
            //.SetCacheable(true)
            //.SetCacheMode(CacheMode.Normal)
            ;
    }

    T IRepository<T>.Get<U>(U id)
    {
        return _conversation.Session.Get<T>(id);
    }

    void IRepository<T>.Save(T obj)
    {
        _conversation.Session.SaveOrUpdate(obj);
    }

    ICriteria IRepository<T>.GetRange(int resultSet, int rangeSize)
    {
        return _conversation.Session.CreateCriteria(typeof (T))
            //.SetCacheable(true)
            //.SetCacheMode(CacheMode.Normal)
            .SetFirstResult(resultSet*rangeSize)
            .SetMaxResults(rangeSize - 1)
            ;
    }

    #endregion
}

This class contains rather basic interactions with NHiberate, if you’re not familiar with the CreateCriteria querying method in NHibernate take a look at Chapter 12. Criteria Queries. Other than that I can at an application level enable or disable output caching for my generic repository, currently I’m still working on getting my second level caching implementation working so right now I have it disabled as you can see it’s commented out.

By returning the ICriteria from the repository it allows us to pass on the full power of NHibernate and allow us to create further data provider specific queries.

Next I created an abstract base class for my actual data providers:

public abstract class DataProviderBase<T>
{
    protected readonly IConversation _conversation;
    protected readonly IRepository<T> _repoistory;

    protected DataProviderBase(IConversation conversation)
    {
        _conversation = conversation;
        _repository = new Repository<T>(_conversation);
    }
}

This base class just holds the fields for the business conversation (or ISession) and my newly created generic repository. Now on to my true concrete implementation of my data provider:

public class EmployeeDataProvider : DataProviderBase<Employee>, IEmployeeDataProvider
{
    [InjectionConstructor]
    public EmployeeDataProvider(IConversation conversation) : base(conversation)
    {
    }

    #region IEmployeeDataProvider Members

    IList<Employee> IEmployeeDataProvider.GetAll()
    {
        return _repository.GetAll().List<Employee>();
    }

    IList<Employee> IEmployeeDataProvider.GetRange(int resultSet, int rangeSize)
    {
        return _repository.GetRange(resultSet, rangeSize).List<Employee>();
    }

    Employee IEmployeeDataProvider.Get(int employeeId)
    {
        return _repository.Get(employeeId);
    }

    void IEmployeeDataProvider.Save(Employee employee)
    {
        _repository.Save(employee);
    }

    IList<Territory> IEmployeeDataProvider.GetTerritories()
    {
        return _conversation.Session.CreateCriteria(typeof (Territory)).List<Territory>();
    }

    #endregion
}

In this class we have the delegation of the IRepository (sitting in the abstract base) and we also have direct access to the NHibernate Session so we can add further methods of any kind. This also allows us the flexibility if you’d rather the EmployeeDataProvider had GetEmpoyees() instead of GetAll() it would allow that easily.

Since the repository itself is not exposed at the provider level this allows us to return the actual results in anyway we want. It allows us to further modify the basic queries by adding NHibernate where clauses to the Criteria if we so choose. Since the actual ICriteria won’t be exposed outside of the data provider we don’t need to worry about client interactions causing database usage. This would also allow us if we added NHibernate LINQ to not be concerned with returning the Queryable results for the same reason.

This pattern would also work directly with LINQ2SQL / LINQ2Entities / DLINQ by changing where the NHibernate session is dealt with and using your entity provider. I feel this is a perfect to the data access patern as it protects the code from becoming too unweilding by basing all communication directly through the ICriteria and giving our data providers concrete result lists.

Let me know what you think!

kick it on DotNetKicks.com

Shout it

BloggingContext.ApplicationInstance.CompleteRequest();

About these ads

5 Comments »

  1. Creating a common generic and extensible NHiberate Repository…

    Thank you for submitting this cool story – Trackback from DotNetShoutout…

    Trackback by DotNetShoutout — January 28, 2009 @ 8:06 pm

  2. [...] Creating a common generic and extensible NHiberate Repository – Chris Marisic shares his implementation of a Generic repository for use with NHibernate [...]

    Pingback by Reflective Perspective - Chris Alcock » The Morning Brew #275 — January 29, 2009 @ 11:20 am

  3. I use the same kind of pattern with linq2Sql, but I kept both the naming of linq and DDD.
    The linq’s tables are behind a generic ITable interface, and the repositories are defined as a specialized interfaces in the domain layer (like IEmployeRepository the equivalent of your IEmployeDataProvider).
    I think it respects the DDD repository naming.
    Creating an in memory implementation of the ITable interface is very easy using a List.AsQueryable !

    Comment by Think Before Coding — January 29, 2009 @ 9:04 pm

  4. [...] class as it’s irrelevant to this post, it’s a class entirely derived from Creating a common generic and extensible NHiberate Repository, the SetAllProperties is just a StructureMap convention, ConversationCommitMode lets you inject [...]

    Pingback by Implementing NHibernate Long Conversation with no HttpModules or AOP build time weaving « dotNetChris @ Marisic.Net — December 18, 2009 @ 3:12 pm

  5. [...] Design — dotnetchris @ 10:22 pm This is a follow up to my original post on this topic Creating a common generic and extensible NHiberate Repository and further progression of it taking advantage of DetachedCriterias and Future [...]

    Pingback by Creating a common generic and extensible NHiberate Repository version 2 « dotNetChris @ Marisic.Net — March 15, 2010 @ 10:23 pm


RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Shocking Blue Green Theme Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 242 other followers

%d bloggers like this: