Previous posts can be found here:

Setting up the repositories for our objects is where this really starts to get fun for me. This is what allows us to work with the persisted objects so easily from our application code, without all the SQL getting in the way. The first thing we want to think about here is what we need the repository to do. Add/Delete/Update all come to mind of course. As well as retrieval of single objects and collections. These will be pretty much standard behaviors across most of our objects. So lets’ look at the interface first:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
using System;
using System.Collections.Generic;
using RecipeTracker.Model;
 
namespace RecipeTracker.Interfaces
{
    public interface IRecipeRepository
    {
        void Add(Recipe recipe);
        void Update(Recipe recipe);
        void Remove(Recipe recipe);
        Recipe GetByID(int id);
        ICollection<Recipe> GetByFamily(string family);
        ICollection<Recipe> GetAll();
        void Dispose();
    }
}
using System;
using System.Collections.Generic;
using RecipeTracker.Model;

namespace RecipeTracker.Interfaces
{
    public interface IRecipeRepository
    {
        void Add(Recipe recipe);
        void Update(Recipe recipe);
        void Remove(Recipe recipe);
        Recipe GetByID(int id);
        ICollection<Recipe> GetByFamily(string family);
        ICollection<Recipe> GetAll();
        void Dispose();
    }
}

Looking at all those methods, there is really only one (GetByFamily) that we won’t need for any repository that we create. So we can put all the other methods into a BaseRepository class. We will need use generics so we can return all the different types however. But first, we need to get a session, so we can add a class for that.

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
using System;
using NHibernate;
using NHibernate.Cfg;
 
namespace RecipeTracker.Repositories
{
    public class SessionProvider<T> where T:new()
    {
        private static ISessionFactory _sessionFactory;
 
        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    var configuration = new Configuration();
                    configuration.Configure();
                    configuration.AddAssembly(typeof(T).Assembly);
                    _sessionFactory = configuration.BuildSessionFactory();
                }
 
                return _sessionFactory;
            }
        }
 
        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }
}
using System;
using NHibernate;
using NHibernate.Cfg;

namespace RecipeTracker.Repositories
{
    public class SessionProvider<T> where T:new()
    {
        private static ISessionFactory _sessionFactory;

        private static ISessionFactory SessionFactory
        {
            get
            {
                if (_sessionFactory == null)
                {
                    var configuration = new Configuration();
                    configuration.Configure();
                    configuration.AddAssembly(typeof(T).Assembly);
                    _sessionFactory = configuration.BuildSessionFactory();
                }

                return _sessionFactory;
            }
        }

        public static ISession OpenSession()
        {
            return SessionFactory.OpenSession();
        }
    }
}

The SessionFactory part should look familar from part 3, the only difference here is that we are initializing the configuration using TypeOf(T) to determine which assembly to find the configuration in rather than TypeOf(MyType). We could probably get away with the latter for this purpose, because there probably won’t be more than one assembly in the application, but why be lazy right? After all, we do need to use generics to deal with the return types anyways.

So now this little bit of code doesn’t need to be handled by our repository, and it can focus on what it does best. So here’s the BaseRepository, it’s nice and simple since it doesn’t need to get its’ own sessions anymore:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
using System;
using System.Collections.Generic;
using NHibernate;
using NHibernate.Cfg;
 
namespace RecipeTracker.Repositories
{
    public abstract class BaseRepository<T> where T: new()
    {
        protected ISession _session = SessionProvider<T>.OpenSession();
 
        public T GetByID(int id)
        {
            return _session.Get<T>(id);
        }
 
        public ICollection<T> GetAll()
        {
            var products = _session
                .CreateCriteria(typeof(T))
                .List<T>();
            return products;
        }
 
        public void Update(T toUpdate)
        {
            using (ITransaction transaction = _session.BeginTransaction())
            {
                _session.Update(toUpdate);
                transaction.Commit();
            }
        }
 
        public void Add(T toAdd)
        {
            using (ITransaction transaction = _session.BeginTransaction())
            {
                _session.Save(toAdd);
                transaction.Commit();
            }
        }
 
        public void Remove(T toRemove)
        {
            using (ITransaction transaction = _session.BeginTransaction())
            {
                _session.Delete(toRemove);
                transaction.Commit();
            }
        }
 
        public void Dispose()
        {
            _session.Close();
            _session.Dispose();
        }
    }
}
using System;
using System.Collections.Generic;
using NHibernate;
using NHibernate.Cfg;

namespace RecipeTracker.Repositories
{
    public abstract class BaseRepository<T> where T: new()
    {
        protected ISession _session = SessionProvider<T>.OpenSession();

        public T GetByID(int id)
        {
            return _session.Get<T>(id);
        }

        public ICollection<T> GetAll()
        {
            var products = _session
                .CreateCriteria(typeof(T))
                .List<T>();
            return products;
        }

        public void Update(T toUpdate)
        {
            using (ITransaction transaction = _session.BeginTransaction())
            {
                _session.Update(toUpdate);
                transaction.Commit();
            }
        }

        public void Add(T toAdd)
        {
            using (ITransaction transaction = _session.BeginTransaction())
            {
                _session.Save(toAdd);
                transaction.Commit();
            }
        }

        public void Remove(T toRemove)
        {
            using (ITransaction transaction = _session.BeginTransaction())
            {
                _session.Delete(toRemove);
                transaction.Commit();
            }
        }

        public void Dispose()
        {
            _session.Close();
            _session.Dispose();
        }
    }
}

Now, look how simple that is to do what we need with our object? No building SQL queries, no creating parameter arrays, or anything. A nice simple bit of code that does just what we need it to do, without all the hassles. We just need a session and the simple commands that it offers, and we can do anything we need. Beautiful, right?

But what if we wanted to do something like get all recipes from a certain family? This will be specific to the object type we need, so we can do that in our implementation of the baseclass (hey, gotta have something in there right!). And this is in fact all that our RecipeRepository class has, one method:

C#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
using System;
using System.Collections.Generic;
using RecipeTracker.Model;
using NHibernate;
 
namespace RecipeTracker.Repositories
{
    public class RecipeRepository : BaseRepository<Recipe>, Interfaces.IRecipeRepository, IDisposable
    {
        public ICollection<Recipe> GetByFamily(string family)
        {
                var products = _session
                    .CreateCriteria(typeof(Recipe))
                    .Add(NHibernate.Criterion.Expression.Eq("Family", family))
                    .List<Recipe>();
                return products;
        }
    }
}
using System;
using System.Collections.Generic;
using RecipeTracker.Model;
using NHibernate;

namespace RecipeTracker.Repositories
{
    public class RecipeRepository : BaseRepository<Recipe>, Interfaces.IRecipeRepository, IDisposable
    {
        public ICollection<Recipe> GetByFamily(string family)
        {
                var products = _session
                    .CreateCriteria(typeof(Recipe))
                    .Add(NHibernate.Criterion.Expression.Eq("Family", family))
                    .List<Recipe>();
                return products;
        }
    }
}

This is some wacky looking code at first. It kind of reminds me of Linq, but what its’ called is HQL (Hibernate Query Language). I haven’t really gotten into it all that much, so I don’t feel qualified to speak about it in detail, but I do find it kinda cool. It may not be as easy as Linq, where you could do a nice Linq query such as

recipeList.Where(n => n.Family = family)

But remember this needs to work on older framework versions as well. I think the HQL is reasonably succinct, and even somewhat elegant. After all reading that you can just about instantly tell what it does. It just creates a criteria on the session for Recipes, and then defines the expression to be evaluated (table.Family = family). Pretty cool. We could probably figure out how to do this with generics pretty easily, but I figure this kind of method is going to be tied to your specific type, and you want to have a descriptive name, and all that.

So after all this I think we are ready to set up some tests. This will be on the next page (damn I’m getting long-winded!)