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);
}
}
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.
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.
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();
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With