Question

As part of my endless NHibernate-inspired DAL refactoring purgatory, I have started to use the Repository pattern to keep NHibernate at arms length from my UI layer. Here's an example of a Load method from a repository.

public StoredWill Load(int id)
{
  StoredWill storedWill;
  using (ISession session = NHibernateSessionFactory.OpenSession())
  {
    storedWill = session.Load<StoredWill>(id);
  }
  return storedWill;
}

I love the fact that my website doesn't know what an ISession is.

Naturally, I started getting lazy initialisation exceptions because the method above doesn't load the StoredWill, it just returns a proxy. When you access the proxy's properties, you get the exception because you are ro longer within the scope of the ISession. I laughed out loud when I realised what was happening.

I have fixed this with:

public StoredWill Load(int id)
{
  StoredWill storedWill;
  using (ISession session = NHibernateSessionFactory.OpenSession())
  {
    storedWill = session.Load<StoredWill>(id);
    string iReallyCouldntCareLess = storedWill.TestatorLastName;
  }
  return storedWill;
}

But it all seems a little silly. Does anyone use a slightly more elegant pattern?

Love you guys.

David

Was it helpful?

Solution

Use dependency injection and pass an ISession to your repository classes through their constructors. That's the only way to allow multiple repositories to participate in the same transaction.

Your website should have some knowledge of an ISession because that's where the transaction boundaries are defined. You can use session-per-request pattern so that the ISession is only referenced in an HttpRequest module or Global.asax. Or you can use a framework or embrace NHibernate and control transactions on the pages.

OTHER TIPS

public StoredWill Load(int id)
{
  StoredWill storedWill;
  using (ISession session = NHibernateSessionFactory.OpenSession())
  {
    storedWill = session.Load<StoredWill>(id);
    // force an eager load within the session
    NHibernateUtil.Initialize(storedWill.TestatorLastName);
  }
  return storedWill;
}

Check out the ncommon framework; it has a nice implementation of fetching strategies that are perfect for this sort of task. You can read more about how this is implemented on the author's blog.

I should also note that your session usage is a little off...you should really be controlling the lifecycle of your session higher up (say at the controller or httpmodule level depending on your front-end). Opening a new session for each repository action is a major anti-pattern in the nhibernate world.

Part of you problem is that you're using Session.Load() instead of Session.Get().

see this article by Ayende Rahien - The difference between Get, Load and querying by id for a in-depth description of the two.

When you call Session.Load() you're telling nhibernate to create a proxy object of the Id that you supply. When doing this nhibernate will not actually call the database to retrive the data. This means that if you Session.Load() with something that does not exits in the database it will throw a Exception. Because you're closing your session before your accessing the object you can't access the data because the proxys session is now closed.

A simple fix would be to change your code to use Session.Get(). This will load your StoredWill class from the database and fill your object with the data that it needs. Note however if you have any inner classes or collections inside you object it will simply create proxies for those. If you need to get everything in one go, you can using one of the many query mechanisims to eager load the parts you need or use projections.

I hope this makes sense :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top