dotNetChris @ Marisic.Net

March 15, 2010

Creating a common generic and extensible NHiberate Repository version 2

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 queries.

I’m going to start with my interface as a jumping off point.

public interface IRepository<T> { 
/// <summary>
/// Adds the specified <see cref="T"/>. 
/// </summary> 
/// <param name="obj">The obj.</param> 
void Add(T obj);  
/// <summary>  
/// Deletes the specified <see cref="T"/>. 
/// </summary> 
/// <param name="obj">The obj.</param> 
void Delete(T obj);  
/// <summary> 
/// Defers the detached crteria execution which will return a result set that is an <see cref="IEnumerable{T}"/>. 
/// </summary> 
/// <param name="detachedCriteria">The detached criteria.</param> 
/// <returns></returns> 
IEnumerable<T> FutureList(DetachedCriteria detachedCriteria); 
/// <summary> 
/// Executes the detached crteria immediately returning a single item <see cref="T"/>
/// This will also cause the execution of any defered queries to be executed. 
/// </summary> /// <param name="detachedCriteria">The detached criteria.</param> 
/// <returns></returns> 
T FutureSingle(DetachedCriteria detachedCriteria); 
/// <summary> 
/// Gets the specified <see cref="T"/>. 
/// </summary> 
/// <typeparam name="U"></typeparam> 
/// <param name="id">The id.</param>
 /// <returns></returns> 
T Get<U>(U id); 
/// <summary> 
/// Executes the detached crteria immediately returning a result set that is an <see cref="IList{T}"/>. 
/// This will also cause the execution of any defered queries to be executed. 
/// </summary> 
/// <param name="detachedCriteria">The detached criteria.</param> 
/// <returns></returns> 
IList<T> QueryList(DetachedCriteria detachedCriteria); 
/// <summary> 
/// Executes the detached crteria immediately returning a single item <see cref="T"/> 
/// </summary> 
/// <param name="detachedCriteria">The detached criteria.</param> 
/// <returns></returns> 
T QuerySingle(DetachedCriteria detachedCriteria); 
/// <summary> 
/// Inserts or updates the specified <see cref="T"/>. 
/// </summary>
/// <param name="obj">The obj.</param> 
void SaveOrUpdate(T obj); 
/// <summary> 
/// Updates the specified <see cref="T"/>. 
/// </summary> 
/// <param name="obj">The obj.</param>
 void Update(T obj); } 

I think my interface is very well defined and with the XMLDoc comments easy to follow what will be implemented. The most notable changes from my original post is the removal of the GetAll and GetRange methods that returned an ICriteria, these always felt like a kludge to me as they clearly bleed concern by allowing the raw ICriteria to be exposed however back then I didn’t have the tools and knowledge available to create a better solution.

The new methods are related to the DetachedCriterias QuerySingle, QueryList and to the Future based queries FutureSingle and FutureList. Future is a newer construct in NHibernate that allows you to specify a query that you want NHibernate to understand and know at some point in the Future it will need this execution so you can batch more than 1 query together and reduce the number of calls to a database. This is a great bonus as the database is usually always the biggest slow down in an application.

On to the actual implementation of the interface

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

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

IList<T> IRepository<T>.QueryList(DetachedCriteria detachedCriteria) {  
 return detachedCriteria.GetExecutableCriteria(_conversation.Session).List<T>(); 
} 

T IRepository<T>.QuerySingle(DetachedCriteria detachedCriteria) {  
 return detachedCriteria.GetExecutableCriteria(_conversation.Session).UniqueResult<T>(); 
} 

T IRepository<T>.FutureSingle(DetachedCriteria detachedCriteria) {  
 return detachedCriteria.GetExecutableCriteria(_conversation.Session).FutureValue<T>().Value; 
} 

IEnumerable<T> IRepository<T>.FutureList(DetachedCriteria detachedCriteria) {  
 return detachedCriteria.GetExecutableCriteria(_conversation.Session).Future<T>(); 
} 

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

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

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

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

void IRepository<T>.Delete(T businessObj) { _conversation.Session.Delete(businessObj); } } 

The one that might be confusing is the _conversation dependency this relates to another post Implementing NHibernate Long Conversation with no HttpModules or AOP build time weaving. You can take a look at this if you haven’t and are curious however it’s not needed to understand my code here as you can really view _conversation to be the raw NHibernate ISession and understand what is going on here.

This class houses the generic CRUD operations that are made generic to allow you to handle any custom object easily. The methods that are once again of interest are the ones I discussed as new additions to my Repository. The beauty of all them regardless is in their simplicity that they can all be written in 1 concise line yet offer immense flexibility.

With the QuerySingle and QueryList methods these allow you to take in a DetachedCriteria and get back either a single object or a IList collection which should be pretty self explanatory from both the code and method names.

The FutureList and FutureSingle are not so much as obvious. As I stated before these allow you to make these happen in the future. In my implementation only the FutureList will really allow you to relegate multiple events into the future but it also makes the most sense since individual lookups are frequently done by indexed columns that should be quick even done in multiple seperate calls. For each call you make to FutureList it will have NHibernate queue up the specified DetachedQuery and wait for one of the following either code causes any of IEnumerables returned to be enumerated which will fire off 1 mulit-query to get all of the result sets or you call FutureSingle.

FutureSingle is some what of a more unusual animal because a regular object doesn’t have the lazy access method that IEnumerables do either it exists, or it doesn’t. There is no transient stage as there is with IEnumerables. To overcome this fact the developers of NHibernate created this transient stage by wrapping object with a generic interface for IFutureValue<T> this gives a construct to have a 3rd stage that you need to call .Value to invoke the actual execution which will process all future queries. In my repository I actually call .Value immediately on a DetachedCriteria being passed into this, why? Because I’d need to return a IFutureValue<T> instead of just T as the result from the method. This in my opinion would be just as much of a kludge as returning ICriteria was from my previous implementation as it bleeds NHibernate understanding logic outside of the repository. This purely a subjective point and if you disagree with my sentiment you could easily return IFutureValue<T> and have a wider range of flexibility with the Future support.

Now on to actual usage of this in a real world scenario. I am going to be taking advantage of a framework I recently learned about called NHibernate Lambda Expressions this allows you to write Criteria and DetachedCriteria queries without the need to rely on magic strings. The point of this post won’t be to cover the usage of this as it should be mostly understandable for my example.

 public class DataProvider : IDataProvider {  
private readonly IRepository<Person> _personRepository;  

public DataProvider(IRepository<Person> personRepository) { _personRepository = personRepository; } 

public IList<Person> GetPersons(State state) { 
  var query = DetachedCriteria.For<Person>() 
 .CreateCriteria<Person>(x => x.PrimaryZip) 
 .CreateCriteria<Zip>(x => x.State) 
 .Add<State>(x => x.StateCode == state.StateCode);  
 return _personRepository.FutureList(query); 
} 

public Person GetPerson(Guid personID) {  return _personRepository.Get(personID); } } 

If you look at my GetPersons method you should see I have a somewhat deep object graph that is realistic, I have a collection of Persons in my database where I assign them a zip code object that contains among other things the zip code and the state that zip code lives in. I create a DetachedCriteria that lets me find all persons that exist in a state and I pass that down to my generic IRepository by delegation instead of inheritance. Many examples similar to my post use inheritance where you will inherit from Repository<Person> instead of having a delegate inside of a non generic class I feel this is the wrong way because it then limits you to having 1 repository per data object instead of being able to drop multiple IRepositorys inside of a single DataProvider.

Taking this a step further I can even remove the need to ever create a physical implementation of Repository<Person> through the use of an inversion of control / dependency injection framework in this case specifically StructureMap. In literally 1 line I can create an infinite amount of IRepositories for any application I need.

For(typeof (IRepository<>)).LifecycleIs(new HybridLifecycle()).Use(typeof (Repository<>)); 

This instructs StructureMap that anytime I need a IRepository<Person> or any other data object that it’s to give it a usage of Repository
completely absolving me of the responsibility of defining a Repository<Person> combining the functionality I’ve outlined in this post it offers a broad range of usage that allows you to interact with NHibernate without ever needing to write a single line of code again except the specific DetachedCriterias which will need written in one shape or form irregardless because they will have custom sql be the end result of them and to just wire up Methods to allow access to the underlying CRUD methods. You could actually expose the generic methods themselves however I feel that is exposing too much logic to be available to an API and prefer to shroud my generic repositories in the classes I call DataProviders as it also lets me group repositories in meaningful ways.

kick it on DotNetKicks.com

Shout it

BloggingContext.ApplicationInstance.CompleteRequest();

About these ads

7 Comments »

  1. Creating a common generic and extensible NHiberate Repository version 2…

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

    Trackback by DotNetShoutout — March 16, 2010 @ 6:48 pm

  2. Hey, nice article.

    One question/comment. If an IRepository is supposed to be sort of your app’s generic interface to fetching and persisting your objects, then do you find it limiting to depend on NHibernate’s criteria-related constructs? I am always cautious about what I have my interfaces depend on, and in specific depending on NHibernate for thta interface forces you to use NHibernate. While that’s not normally a bad thing, it does presuppose that you’ll always be using an RDBMS for persistence, which might not be the case always.

    I guess what I’m getting at is, do you find that dependency to be onerous? How would you handle it if you’re doing a web app and you wanted to start storing using Google Big Tables or Azure Tables?

    Comment by paul — March 18, 2010 @ 3:21 pm

    • That’s the reason why I’m a fan of using delegation for my IRepository because none of my model ever depends on an IRepository all of my model dependencies rely on the data provider classes if you look at my example for public class DataProvider : IDataProvider.

      This way my model is compeltely agnostic of my database all dependencies on NHibernate exist behind the data provider. So if I ever wanted to switch to something else I would just need to create a new implementation of my IDataProvider interface and away I go.

      Also with the DetatchedCriteria this allows me to offer almost full functionality of NHibernate queries at the DataProvider level without needing to expose the raw ISession which I feel is giving the DataProvider too much rope to hang itself with especially since that would allow a developer to accident close a session or Flush a session at the wrong time instead of correctly allowing the session management pattern I’ve discussed in other articles to manage the transactions.

      Comment by dotnetchris — March 18, 2010 @ 8:47 pm

      • Right, I understand the model being agnostic of yoru database, but somewhere in your application you still have consumers of the repository code, and you can’t swap out implementations without rewriting all those, since the IRepository interface defines that contract.

        Comment by paul — March 19, 2010 @ 2:22 am

      • True but that’s entirely reasonable, my DataProviders are meant to be database agnostic, that IRepository interface is meant to make working with NHibernate be incredibly easy to roll out the basic CRUD operations to any single object in my domain model without writing a single line of code.

        Doing something magical like this against stored procs would be basically impossible aside from writing you own full ORM implementation to do parsing of objects. It’s reasonable to expect if you change databases that there can be a large amount of code to be replaced. With NHibernate you actually have a reasonable expectation that you can even switch databases without having to replace any of your code base (assuming all of the features you took advantage of in NH are in that database)

        Comment by dotnetchris — March 19, 2010 @ 3:21 am

      • Understood, and I wasn’t trying to sharpshoot you, it’s a solid design for most scenarios. My point was simply that your design assumes that the repository is in fact a relational database, since that’s all NHibernate supports. So if you decide later to use a non-relational data store (e.g. a document db, flat xml, cloud stuff, an object db) then your IRepository interface won’t support that.

        Comment by Paul — March 20, 2010 @ 12:08 pm

      • Agreed it wouldn’t support that but that’s why this is specifically an NHibernate repository ;)

        The problem with creating an absolutely generic repository is at some point you actually have to supply it with actions that will do something meaningful at that backingstore level which is very hard if not impossible to genericize to get an idea look at what you’d have for an interface for a super generic Repository

        public interface IRepository<T>
        {
        void Add(T obj);
        void Delete(T obj);
        void SaveOrUpdate(T obj);
        void Update(T obj);

        The simple crud operations are easy but the problem comes with querying, even the basic get statement starts the rabbit hole

        T Get<U>(U id);

        This will work assuming every object you have has a single unique identifier (good practice obviously) but that doesn’t mean there aren’t objects that have combinational keys which would be impossible to support in generics.

        Now own to the query level
        IList QueryList( what goes here? );
        T QuerySingle( what goes here? );

        Once again your left with very little knowledge of how to define an action that will let you query the backing store at this generic of a level. I suppose theoretically it would be possible to make each of these methods take a rather complex series of action & func statements that would allow you to define how to read the primary key for the get statement and how to query the backing store but at that point you’re going to add alot of complexity and very little benefit when if you make your repository code specific to the backing store and then hide that behind service interfaces you eliminate the majority of all the boiler plate code you would right and keep the complexity from rising too far.

        Comment by dotnetchris — April 4, 2010 @ 1:48 am


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: