views:

314

answers:

3

There are several similar questions on this matter, by I still haven't found enough reasons to decide which way to go.

The real question is, is it reasonable to abstract the NHibernate using a Repository pattern, or not?

It seems that the only reason behind abstracting it is to leave yourself an option to replace NHibernate with a different ORM if needed. But creating repositories and abstracting queries seems like adding yet another layer, and doing much of the plumbing by hand.

One option is to use expose IQueryable<T> to the business layer and use LINQ, but from my experience LINQ support is still not fully implemented in NHibernate (queries simply don't always work as expected, and I hate spending time on debugging a framework).

Although referencing NHibernate in my business layer hurts my eyes, it is supposed to be an abstraction of data access by itself, right?

What are you opinions on this?

+2  A: 

Good quiestions. I was also thinking about them a few days ago.

Actually, try out NHibernate 3.0 alpha (or the current trunk), its new LINQ provider is much greater than the previous ones. (So far I only found one method which is not working, but it is possible to hook in your own mechanism if you run into something it doesn't support by default.) I had no problems (yet?) with using the current trunk. You can find a "nightly" build on the http://www.hornget.net/packages/ site, along with a FluentNHibernate build against it. Fluent really increases your productivity if you know how to use it. The SO community really helped me with that, too.

If you are okay with your business layer having a direct dependency on NHibernate, or you are writing a smaller application which remains maintainable without this kind of abstraction, you're good to go without the repository pattern. However, if you do it right, it can save you a lot of redundant coding.

The reason for abstracting it isn't only useful because then you can replace NHibernate later with another ORM, but it is a good practice because of a concept called Separation of Concerns. Your business logic layer shouldn't care or know anything about how to access the data it works with. This makes maintaining the application or its different layers easier, which also makes teamwork easier: If X creates the data access layer, and Y writes the business logic, they don't have to know each others' work in detail.

Exposing an IQueryable<T> is a very good idea, and that is exactly what many repository implementations are doing right now. (And me too, although I preferred to write it in a static class.) And of course you'll have to expose some methods to insert or update an entity, or methods for beginning and commiting transactions, if you want to. (The BeginTransaction should just return an IDisposable to avoid leaking out an NHibernate interface, and that'll be fine.)

I can give you some directions: check out SharpArchitecture's or FubuMVC Contrib's implementations to get some ideas about how do do it right, and this is how I solved it.

Venemo
Thanks for the answer. Actually, what I wanted to say is that using HNibernate to query data directly shouldn't expose database implementation to the business layer significantly, once you map these two models together. I believe that was the original idea behind the ORM concept. Personally, the truth is that I don't want to use it directly, but a repository pattern (if I don't expose IQueryable) requires additional coding. Using Linq would be lovely, if it were reliable. Maybe I will try the alpha version :).
Groo
I had no problems (yet?) with using the current trunk. Updated my answer.
Venemo
+2  A: 

I would simply say a big YES! have a Repository pattern, keep things abstract!

System.ArgumentException
A: 

I personally prefer still abstracting out the NHibernate into a repository pattern. The reason is I might still have other implementations of the repository for caching, mocking for units tests, etc. And I also make use of IQueryable with my repository, though I make IRepository extend IQueryable rather than expose a property on IRepository of type IQueryable.

Another repository point. Some people suggest not making it generic and having the type identification at the method level (i.e. repository.Load). This, however, assumes that there will be a single repository that knows how to deal with all types. I'm not a big fan of this notion of a single monolithic repository. What if you're dealing with multiple databases? Or multiple persistence mechanisms? Or some data types stay fairly static and can be cached, but others can't. This is why I like a separate repository instance for each type.

Rich