bretddog
bretddog

Reputation: 5519

NHibernate ISession lifecycle; When is it ok to create/dispose inside each repository method?

I'm working with single-tier, single-user applications, with FluentNHibernate. With multiple threads, triggered by time triggers and incoming socket message triggers.

What requirements will determine if I can create/dispose the ISession inside each method of the repositories, or if I need to maintain the ISession lifecycle over multiple calls, maybe from program start to end?

For example, does lazy-load require session to be maintained? And if I don't use lazyload, for what other reason should I maintain the ISession?

Currently my repository methods look like below, but I wonder if I'm doing it wrong..

public class ProductRepository
{
    public void Delete(Product product)
    {
        using (ISession session = FNH_Manager.OpenSession())
        {
            using (ITransaction transaction = session.BeginTransaction())
            {
                session.Delete(product);
                transaction.Commit();
            }
        }
    }

class FNH_Manager
{
    private static Configuration cfg;
    private static ISessionFactory sessionFactory;

    public static void ConfigureSessionFactory()
    {
        sessionFactory = CreateSessionFactory();
    }

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

EDIT1: Attempt to handle "session per call":

   public class EmployeeRepository
   {  
        public static void Delete(Employee employee)
        {
            using (ISession session = FNH_Manager.OpenSession())
            {
                using (ITransaction transaction = session.BeginTransaction())
                {
                    if (Employee.Id != 0)
                    {
                      var emp =  session.Get(typeof(Employee), employee.Id);
                      if (emp != null)
                      {
                        session.Delete(emp);
                        transaction.Commit();
                      }
                    }
                }
            }
        } 

Upvotes: 3

Views: 2876

Answers (3)

Chingiz Musayev
Chingiz Musayev

Reputation: 2962

I think you should use UnitOfWork pattern per thread. On thread start create ISession and initialize UnitOfWork with it. Repositories use UnitOfWork with that signle ISession. At the end of thread execution commit the changes or rollback if there was conflict with other threads.

Upvotes: 3

vidstige
vidstige

Reputation: 13079

The Product is not associated with any session when beeing deleted. It is a so called detached object. To use it within the session for example deleting it you need to first associate it with the currently opened session. There are several ways to achive this:

  1. Keep the session open. If the same session is opened when the Product is loaded as when it is deleted, it will work fine.
  2. Reload the object, but using ISession.Get() or ISession.Load().
  3. Re-attach the object to the newly opened session session with ISession.Lock()

Otherwise you'll probably get StaleStateExceptions and the like.

Remeber to read up on the NHibernate documentation

Upvotes: 1

Kevin Pang
Kevin Pang

Reputation: 41442

The session must be open when you reference a lazy-loaded field, so if you're relying on lazy-loading outside of your repository you'll need to manage the session lifespan somewhere higher up.

If you don't use lazy-loading, there's also the matter of whether you need to support multiple actions in one transaction. For example, if you delete a product AND some other data in one go, you'd want that to happen in one transaction in the same session (otherwise you might delete the product, have some code throw some exception, and never delete the other data, which may end up with orphan records or a corrupt state in your database).

Upvotes: 5

Related Questions