Tuesday, October 18, 2011

Another NHibernate Repository

October 18, 2011 Posted by Jason Irwin No comments
I’ve been having a lot of fun with NHibernate recently and, during my spare time, have a few pet projects that I like to work on to improve my skillset (especially because it looks like my company is going to give an ORM a test run in the not too distant future). Everyone has their opinion on whether or not a Repository with an ORM is a good thing or a bad thing, and I’m not going to rehash any such arguments, except to say the following:
  • I needed to stop implementing the same old LoadSomethingById, UpdateSomething, SaveSomething, etc. methods for every single data type in my service layer. I found myself re-inventing the wheel, albeit with different naming conventions, over and over again
  • While NHibernate does provide a layer of abstraction in and of itself, I was reluctant to couple a particular ORM to my solution (i.e. call _session.Load<SomeType>(id) directly from my controller/codebehind/whatever)
So, as a learning exercise (like the world needed another one…) I created my own version of a Repository with an NHibernate solution as the default implementation. No doubt it’s not perfect but it was pretty worthwhile from an educational standpoint and I feel it is far cleaner than my previous approach. Feel Free to supply any constructive criticism you see fit.

My implementation is similar to a number already out there, aiming for a minimal set of non-specialized operations in my repository contract. Included is a pretty sweet simple FindMany (and FindManyFuture counterpart) method which takes an expression and uses the expression as my queryover’s filter. Combined with this is the ability to specify a limit on the number of items returned and the number of items you want to skip over. Both are useful if paging is necessary and I always like to specify a limit on all of my queries to stop any chance of returning an overly large number of records which will then hydrate objects and slow my application to a crawl.   Most of the other methods are pretty straightforward and correspond to common use cases when using any ORM.
My initial feeling is that this implementation as-is takes care of the bulk (~70%) ordinary  queries. For extraordinary queries, and those used repeatedly that I would like to reuse, I use extension methods rather than a service layer (as in the example below). This provides specific functions to specific repositories (based on the generic type) and allows me to use a single 

All in all, it looks a little something like this:

Here is the repository interface:
public interface IRepository<T, TId>
{
        T Get(TId id);
        IList<T> GetAll();
        T SaveOrUpdate(T entity);
        void Delete(T entity);
        ISession Session { get; }
        IList<T> FindMany(Expression<Func<T, bool>> expression = null, int skip = 0, int take = int.MaxValue);
        IEnumerable<T> FindManyFuture(Expression<Func<T, bool>> expression = null, int skip = 0, int take = int.MaxValue);
        T FindOne(Expression<Func<T, bool>> expression);
        T Load(TId id);
        T Save(T entity);
        T Update(T entity);
        void Delete(TId id);
}

Here is the default implementation:


  public class NHibernateRepository<T, TId> : IRepository<T, TId> where T : class
    {
        private readonly ISession _session;

        public NHibernateRepository(ISession session)
        {
            _session = session;
        }

        public virtual ISession Session
        {
            get { return _session; }
        }

        public IList<T> FindMany(Expression<Func<T, bool>> expression = null, int skip = 0, int take = int.MaxValue )
        {
            return expression != null ? Session.QueryOver<T>().Where(expression).Skip(skip).Take(take).List() : Session.QueryOver<T>().Skip(skip).Take(take).List();
        }

        public IEnumerable<T> FindManyFuture(Expression<Func<T, bool>> expression = null, int skip = 0, int take = int.MaxValue)
        {
            return expression != null ? Session.QueryOver<T>().Where(expression).Skip(skip).Take(take).Future<T>() : Session.QueryOver<T>().Skip(skip).Take(take).Future<T>();
        }

        public T FindOne(Expression<Func<T, bool>> expression)
        {
            return Session.QueryOver<T>().Where(expression).SingleOrDefault();
        }

        public virtual T Load(TId id)
        {
            return Session.Load<T>(id);
        }

        public virtual T Save(T entity)
        {
            Session.Save(entity);
            return entity;
        }

        public virtual T Update(T entity)
        {
            Session.Update(entity);
            return entity;
        }

        public virtual void Evict(T entity)
        {
            Session.Evict(entity);
        }

        public virtual void Delete(T entity)
        {
            Session.Delete(entity);
        }

        public virtual void Delete(TId id)
        {
            Session.Delete(Session.Load<T>(id));
        }


        public virtual T Get(TId id)
        {
            return Session.Get<T>(id);
        }

        public virtual IList<T> GetAll()
        {
            ICriteria criteria = Session.CreateCriteria(typeof (T));
            return criteria.List<T>();
        }

        public virtual T SaveOrUpdate(T entity)
        {
            Session.SaveOrUpdate(entity);
            return entity;
        }
   }

Example Extension Method


public static class ShopperExtensions
{
 public static Shopper GetShopperBySecurityToken(this IRepository<Shopper,int> repository, string securityToken)
 {
  return repository.Session.CreateCriteria(typeof (Shopper))
   .CreateAlias("ShopperSecurityProfile", "profile")
   .Add(Property.ForName("profile.SecurityToken").Eq(securityToken))
   .UniqueResult<Shopper>();
 }
}

Basic Usage



var shopperRepository = ObjectFactory.Container.GetInstance<IRepository<Shopper,int>>();

int shopperID = 123456;
var shopper = shopperRepository.Get(123456);

// OR USING SECURITY TOKEN AND EXTENSION METHOD

var shopper = shopperRepository.GetShopperBySecurityToken(securityToken);


In the above code you can see an example of using the Get method to get a particular shopper based on their ID and also a second example where an extension method is used to return a shopper based on their security token. (Note, in real-world code I would probably use constructor/property injection for my dependencies but go directly to the container in this example (ObjectFactory.Container…) for the sake of brevity.) The one change I definitely need to make is to remove the dependency on ISession from the repository interface. This (and now that I think of it maybe the Evict method) is the only place in the solution where the specific ORM solution leaks into my solution (so to speak). This property is only necessary so that any extension methods defined have a session they can use to hit the database.


Sunday, October 16, 2011

Book Review - The Well Grounded Rubyist

October 16, 2011 Posted by Jason Irwin No comments

Disclosure: I recently received review copies of two books in Manning’s Ruby series. The first, and the subject of today’s review is The Well Grounded Rubyist by David A. Black.

black2_cover150

These days it feels as though one couldn’t throw a rock in a major metropolitan area without hitting a ruby developer. Worse still, each appears more enthused than the last. This enthusiasm is either infectious or annoying, depending on the individual, but as a .NET developer by day I’m admittedly intrigued to see what all the fuss is about. While I enjoy the .NET stack and will be using it professionally for the foreseeable future, it’s time to balance my skill set somewhat and Ruby (on Rails) may be just the tonic - hence my request to review this title. Expect some future Ruby/Rails/VIM related posts!


I haven’t yet found a good reference explaining the different naming conventions employed by Manning in their series’ titles (let me know if one exists and I’ll post a link). The term “Well Grounded” had a similar effect to a realtor describing a property as “rustic”, and I I was originally skeptical, taking the title to imply something a little more basic and less thorough than this book actually is. I was completely mistaken - light and fluffy this title is not. Instead it is an enjoyable and detailed introduction to programming with Ruby, valuable to polyglot programmers and novices alike. I’ve read the title cover to cover (with many highlights along the way) and it will undoubtedly remain on my bookshelf long term as a useful reference to the Ruby language.


The author, David A Black, focuses solely on the core Ruby programming language, purposefully avoiding libraries and frameworks (no rails here) in favor of getting deep into the language itself - a wise move that allows a consistent focus and detail oriented approach. The book begins with an overview of the Ruby installation and command line tools which clarified much for me - a novice Ruby programmer. The remainder of the book iteratively builds knowledge of the Ruby language, explaining core mechanisms common to other languages (objects/classes/scope/etc.), moving onto Ruby’s myriad of in-built classes and finally delving into dynamic programming and introspection.


The book is well written, code samples are often simple but always effective and after reading the book I feel very comfortable getting started and writing some code of my own. What I enjoyed most about this title was David A Black’s insight into the Ruby programming language. Throughout the book he provides commentary on why things are they way they are. He doesn’t simply (as is often the case with similar titles) describe a construct and then move forward - he goes to great length to rationalize the usage of constructs and advises the reader when and why they should be used. Similarly he touches on the evolution of the language, citing mechanisms that have changed from one revision to the next - describing the problem and the fix - and also warning the reader when mechanisms he is describing are likely to change in the future. I find this type of insight extremely interesting and beneficial in my education on the language. I’ll be looking out for more titles by the author in the future.


If there are two things that I would have liked to have seen it is some coverage on debugging and testability. As I mentioned earlier, the book focuses on only the core language itself and perhaps these are not core language constructs, so to speak. However, for me, knowing how the language facilitates debugging and (automated) testing are key concerns and I was a little disappointed to reach the final chapter with little being said on either.


At the end of the day this is a great book, full of useful advice and worthy as an introduction to Ruby or a reference for seasoned developers. It covers Ruby 1.9.1 so is up to date and very relevant. I heartily recommend it!