How to fix the fake NHibernate boot error "session or session not closed"?

I am developing a website with ASP.NET MVC, NHibernate, and Fluent Hibernate and am getting a " session or session closed " error when trying to access a child.

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 cards:

 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 Factory session 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 the database using this code:

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

But when I try to access the child Image using this code

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

I get this error:

Initialization [Entities.ImageGallery # 1] - failed to lazily initialize the role collection: Entities.ImageGallery.Images, session or session closed

Does anyone know how I can fix this?

Many thanks!

Edit

My GetById Method:

  public ImageGallery GetById(int id) { using(ISession session = NHibernateSessionFactory.OpenSession()) { return session.Get<ImageGallery>(id); } } 
+4
source share
3 answers

Presumably, your GetById closing the session. This can be explicit or using the using statement.

The best approach to session management is the Open Session in View template. NHibernate sessions are cheap to create, so create them at the beginning 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 the DI container, we can have a session injected with instances processed on demand.

 // ninject example Bind<ISession>() .ToMethod( ctx => sessionFactory.GetCurrentSession() ) .InRequestScope(); 
+8
source

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

I usually do this by creating a session instance before all calls to the repository, passing the session link to the repository constructor, and using this link inside the repository class

+3
source

I'm not sure if this applies here, but this (or at least usually) is a common problem in Java MVC frameworks. This usually happens when you create a session inside your action. When your action completes, the session object goes out of scope and the session closes / resets. Then, when the view tries to display a collection of objects that you received, it tries to load the collection with lazy loading using a closed session.

If you use dependency injection in your project, you can create your own DI environment to create a session for you and pass it as a constructor argument to your controller. You can also specify that the DI container should span the NHibernate session the same as your HTTP request. This will save the session until the request ends (the view has completed rendering).

I used Autofac as our DI container on the project and worked and was very pleased with it.

+2
source

Source: https://habr.com/ru/post/1305167/


All Articles