Implementing The Repository Pattern With NHibernate
Implementing The Repository Pattern With NHibernate
This blog post is a continuation from my previous post, which enumerates the merits of the Repository design pattern. Here, I'm going to show you a great way to implement the Repository pattern. Just to recap, the Repository Pattern is essentially this interface: public interface IRepository<T> { T Get(object id); void Save(T value>); void Update(T value); void Delete(T value); IList<T> GetAll(); } Note: The strength of this interface is its simplicity. Its Achilles' heel is that lazyloading will have to be disabled in order to reference associated objects. If this is a deal-breaker for you, check out the Unit of Work facade. Now for the hard part: implementing the interface. We will be using NHibernate to accomplish this. Why NHibernate? NHibernate is one of the most popular ORMs in existence, and for good reason. 1. It's open source.
2. It covers the object-relational impedance mismatch very well (support for inheritance/polymorphism/composition with configurable implementation). 3. You can generate the entire system database with one line of code. 4. Combined with FluentNHibernate, follows the convention over configuration design paradigm. 5. It's very flexible in terms usability, offering you abstract/ease-of-use functionality or control of all fine-tuned minut imaginable. That being said, NHibernate is more than adequate for task at hand. The example world that I'm going to model simply consists of monkeys and bananas, where monkeys can have multiple bananas, like so: public class Monkey { public virtual int Id { get; set; }
public virtual string Name { get; set; } public virtual bool FlingsPoo { get; set; } public virtual IList<Banana> Bananas { get; set; } } public class Banana { public virtual int Id { get; set; } public virtual string Color { get; set; } } NHibernate uses "mappings" to tie the classes to the database, and while it's possible to fulfill this example using FluentNHibernate auto mapping, most people prefer the control of the classic Fluent mappingclasses, so that's what we'll use. public class MonkeyMap : ClassMap<Monkey> { public MonkeyMap() { Id(x => x.Id); Map(x => x.Name); Map(x => x.FlingsPoo); HasMany<Banana>(x => x.Bananas) .Not.LazyLoad(); } } public class BananaMap : ClassMap<Banana> { public BananaMap() { Id(x => x.Id); Map(x => x.Color); } } That should take care of the database mapping. And now for the meat and potatoes: public class NHibernateRepository<T> : IRepository<T> where T : class { protected Configuration config; protected ISessionFactory sessionFactory;
public NHibernateRepository() { config = Fluently.Configure() .Database( MsSqlConfiguration .MsSql2008 .ConnectionString(@"Data Source=SQLEXPRESS;Initial Catalog=TestDB;Integrated Security=True")) .Mappings(m => m.FluentMappings.AddFromAssemblyOf<NHibernateRepository<T>>()) .BuildConfiguration(); sessionFactory = config.BuildSessionFactory(); } public void Save(T value) { using (var session = sessionFactory.OpenSession()) using (var transaction = session.BeginTransaction()) { session.Save(value); transaction.Commit(); } } } That's really all there is to it. I leave Get/Update/Delete/GetAll out as an exercise for the reader to implement (Hint: they're almost exactly like Save). Change the connection string to point at your test database and we should be good to go. What are we waiting for? Let's put a monkey in the database! Monkey m = new Monkey() { Name = "George", FlingsPoo = true }; IRepository<Monkey> mRepo = new NHibernateRepository<Monkey>(); mRepo.Save(m);