Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix a NHibernate lazy loading error "no session or session was closed"?

I'm developing a website with ASP.NET MVC, NHibernate and Fluent Hibernate and getting the error "no session or session was closed" when I try to access a child object.

These are my domain classes:

public class ImageGallery {
    public virtual int Id { get; set; }
    public virtual string Title { get; set; }
    public virtual IList<Image> Images { get; set; }
}

public class Image {
    public virtual int Id { get; set; }
    public virtual ImageGallery ImageGallery { get; set; }
    public virtual string File { get; set; }
}

These are my maps:

public class ImageGalleryMap:ClassMap<ImageGallery> {
    public ImageGalleryMap() {
        Id(x => x.Id);
        Map(x => x.Title);
        HasMany(x => x.Images);
    }
}

public class ImageMap:ClassMap<Image> {
    public ImageMap() {
        Id(x => x.Id);
        References(x => x.ImageGallery);
        Map(x => x.File);
    }
}

And this is my Session Factory helper class:

public class NHibernateSessionFactory {
    private static ISessionFactory _sessionFactory;
    private static ISessionFactory SessionFactory {
        get {
            if(_sessionFactory == null) {
                _sessionFactory = Fluently.Configure()
                    .Database(MySQLConfiguration.Standard.ConnectionString(MyConnString))
                    .Mappings(m => m.FluentMappings.AddFromAssemblyOf<ImageGalleryMap>())
                    .ExposeConfiguration(c => c.Properties.Add("hbm2ddl.keywords", "none"))
                    .BuildSessionFactory();
            }
            return _sessionFactory;
        }
    }
    public static ISession OpenSession() {
        return SessionFactory.OpenSession();
    }
}

Everything works fine, when I get ImageGallery from database using this code:

IImageGalleryRepository igr = new ImageGalleryRepository();
ImageGallery ig = igr.GetById(1);

But, when I try to access the Image child object with this code

string imageFile = ig.Images[1].File;

I get this error:

Initializing[Entities.ImageGallery#1]-failed to lazily initialize a collection of role: Entities.ImageGallery.Images, no session or session was closed

Someone know how can I fix this?

Thank you very much!

Edit

My GetById method is:

    public ImageGallery GetById(int id) {
        using(ISession session = NHibernateSessionFactory.OpenSession()) {
            return session.Get<ImageGallery>(id);
        }
    }
like image 925
MCardinale Avatar asked Mar 25 '10 22:03

MCardinale


People also ask

What is lazy loading in Nhibernate?

Any association, whether it be a many-to-one or a collection is lazy loaded by default, it requires an Open ISession. If you have closed your session, or if you have committed your transaction, you can get a lazy load exception that it cannot pull in those additional objects.

How do I know what version of nhibernate I have?

On visual studio, go to project using nhibernate then open references folder, righ click over nhibernate assembly and click properties. You'll should be able to see the the version. You could do something similar outside visual studio, right clicking over nhibernate. dll and checking assembly version on details tab.


2 Answers

Presumably, your GetById is closing the session. This could be explicit, or via a using statement.

A better approach to session management is the Open Session in View pattern. NHibernate sessions are cheap to create, so create one at the start of each request, and close it at the end.

// in global.asax.cs

public void Application_Start()
{
    BeginRequest += delegate {
        CurrentSessionContext.Bind( sessionFactory.OpenSession());
    };

    EndRequest += delegate {
        var session = sessionFactory.GetCurrentSession();
        if (null != session) {
            session.Dispose();
        }
        CurrentSessionContext.Unbind(sessionFactory);
    };
}

// in your NHibernateSessionFactory class
public static ISession OpenSession() {
    return SessionFactory.GetCurrentSession();
}

Using a DI container, we can have the session injected with instances scoped per-request.

// ninject example
Bind<ISession>()
    .ToMethod( ctx => sessionFactory.GetCurrentSession() )
    .InRequestScope();
like image 112
Lachlan Roche Avatar answered Nov 08 '22 10:11

Lachlan Roche


The session used to get the ig must be alive when accessing ig.Images[1]

I usually do this by instantiating the session before all repository calls, passing the session reference to the the repository constructor and using that reference inside the repository class

like image 42
Catalin DICU Avatar answered Nov 08 '22 12:11

Catalin DICU