I just had a mayor “aha”-experience, and I really need to write it down while it’s still in my head. The reason I tell you this, is that this post will seem more complicated than what I usually write.

Back on track. Tonight I was doing some of my awesome code-writing. Everything was going good and I was really enjoying using both NHibernate and my newly added StructureMap IOC, but then, while writing just another repository, the little voice inside my head suddenly yelled “You need to rewrite all of this, if Entity Framework 4.0 really rock that much!!”.

The little voice was so right. While if was thinking that my code were Scott Guthrie-worthy, I realized that I was tying my whole data layer specifically to NHibernate – not good.

Besides that, I was ignoring both the “loosely-coupled-strategy”an also DRY (Don’t repeat yourself), since nearly all of my repository contained “GetById”, “GetAll”, “Insert” and “Delete” methods.

Enough talk – if you want to do repositories right, you do them with the IRepository pattern. Before we start, you should know that this (of course) can’t be done without using some kind of IOC (Dependency Injection) in your solution.

In the following example I’m going to use NHibernate and StructureMap.

 

1. Create a template repository for your data layer.

First thing is to structure a repository class that contains all your “shared” methods:

   1: namespace Example.Repositories
   2: {
   3:     public class Repository where T : class
   4:     {
   5:         //Fields
   6:         private readonly IUnitOfWork _unitOfWork;
   7:  
   8:         public Repository(IUnitOfWork unitOfWork)
   9:         {
  10:             _unitOfWork = unitOfWork;
  11:         }
  12:  
  13:         //Query methods
  14:         public virtual T GetById(int id)
  15:         {
  16:             return _unitOfWork.CurrentSession.Get(id);
  17:         }
  18:  
  19:         public virtual IEnumerable GetAll()
  20:         {
  21:             return _unitOfWork.CurrentSession.CreateCriteria(typeof (T)).List();
  22:         }
  23:  
  24:  
  25:         //Insert/delete methods
  26:         public virtual void Insert(T entity)
  27:         {
  28:             _unitOfWork.CurrentSession.SaveOrUpdate(entity);
  29:         }
  30:  
  31:         public virtual void Delete(T entity)
  32:         {
  33:             _unitOfWork.CurrentSession.Delete(entity);
  34:         }
  35:     }
  36: }
 
If you haven't used the “where T : class”-thing, don’t be scared. You’ll automatically understand it’s behavior when you get to the bottom of this post.
 
Besides that, everything should be familiar to you. It’s just a simple repository where we don’t declare the specific object type.
 
Next, we need to wrap an interface to our repository. If you’re still typing your interfaces by yourself, try moving the cursor to “public class Repository” and hit CTRL+SHIFT+R. This brings a little ReSharper menu (If you of course have ReSharper). Select “Extract interface”. ReSharper will suggest the name IRepository (which is fine with us). We do however want to place the interface in a separate file, and extract all the methods, like this:
image
 
You should now get a new IRepository.cs file containing this code:
   1: namespace Example.Repositories
   2: {
   3:     public interface IRepository where T : class
   4:     {
   5:         T GetById(int id);
   6:         IEnumerable GetAll();
   7:         void Insert(T entity);
   8:         void Delete(T entity);
   9:     }
  10: }

Also notice that ReSharper automatically jumps into Repository.cs and change the class declaration to:

   1: public class Repository : IRepository where T : class

Things getting sexy now, huh?

 

2. Tell StructureMap about IRepository’s behavior

We can now move on to our bootstrapper (or whatever you use to initialize StructureMap). This is very simple. This is my bootstrapper:

   1: public virtual void BootstrapStructureMap()
   2: {
   3:     ObjectFactory.Initialize(
   4:         x =>
   5:             {
   6:                 x.Scan(scanner =>
   7:                            {
   8:                                scanner.TheCallingAssembly();
   9:                                scanner.WithDefaultConventions();
  10:                            });
  11:                 x.ForRequestedType(typeof(IRepository<>)).TheDefaultIsConcreteType(typeof(Repository<>));
  12:                 x.AddRegistry(new NHibernateRegistry());
  13:             });
  14: }


Notice line 11, “x.ForRequestedType(typeof(IRepository<>)).TheDefaultIsConcreteType(typeof(Repository<>));”.

 

3. Time for some repository-action

Alright, really simple scenario: I have a domain class, lets call it Profile (like a user profile). Also, lets say we have a ASP.NET MVC project, where we in our HomeController’s default/index action want to write out the first profile’s full name.

I’ll just give you the code. StructureMap will (behind the scenes) inject the specific repository when we ask for it.

 

   1: namespace Example.Controllers
   2: {
   3:     public class HomeController : Controller
   4:     {
   5:         //Fields
   6:         private IRepository _profileRepository;
   7:  
   8:         public HomeController(IRepository profileRepository)
   9:         {
  10:             _profileRepository = profileRepository;
  11:         }
  12:  
  13:         //
  14:         // GET: /Test/
  15:         public string Index()
  16:         {
  17:             var profile = _profileRepository.GetAll().First();
  18:             return profile.Fullname;
  19:         }
  20:     }
  21: }


Omfg, isn’t that sexy? I think!

Have fun deleting your wet repositories and enjoy a DRY IRepository.

Btw, you may be asking yourself “What if I want to include a method that’s specific to only one domain object?”. If you did, you could try playing around yourself, or wait for my next post about exactly that :)