0

The question is to get all parents whose all children age is above a certain age.The expected output should also include the children list with their parent.

I have the following...

session.CreateQuery("select p, c from Parent as p left outer join p.Children as c where c.Age!= :age")
 .SetParameter("age", somevalue);

But I am getting the following error:

Initializing[ns.Parent #18]-failed to lazily initialize a collection
of role: ns.Children, no session or session was closed

This is my code:

class Parent {
   public virtual int Id { get; set; }
   public virtual IList<Child> Children { get; set; }
}


class Child {
   public virtual int Id { get; set; }
   public virtual int Age{ get; set; }
   public virtual int ParentId { get; set; }   
}

  //the mapping

  public class ParentMap : ClassMap<Parent>
    {
        public ParentMap()
        {
            this.Id(t => t.Id);         
            this.HasMany(t => t.Child).Not.LazyLoad();
        }
    }

    class ParentRepository : IParentRepository {

        public IEnumerable<Parent> GetAll()
        {

                using (var session = _factory.OpenSession())
                {
                    session.CreateQuery("select p, c from Parent as p left outer join       p.Children as c where c.Age!= :age")
                    .SetParameter("age", somevalue);

                    return result.Distinct().ToArray();
                }

        }
    }

//In a different class I call GetAll.
var data = parentRepository.GetAll();
//at the following line that i get the error. 
    IEnumerable<Contracts.Parent> parents = Mapper.Map<IEnumerable<ns.Parent>,        IEnumerable<Contracts.Parent>>(data.ToArray());

I use AutoMapper to map the object to another similar objects(Parent and Child). The Parent and the Child in the Contract namespace has exactly the same type of properties

user1163205
  • 51
  • 1
  • 3
  • As indicated by the error message, you are attempting to call `CreateQuery` with no open session. Please ensure you are not closing/disposing your session, or post the code where you call `CreateQuery`. – JW Lim Mar 13 '14 at 02:26

1 Answers1

0

NHibernate and its ISession do require a different approach then using statement (usually). What we do prefer is to have a session - to be opened as late as possible (e.g. even some lazy techniques) and keep it open (if opened) as long as possible.

In case of web applications, the most common approaches are (see Effective NHibernate Session management for web apps)

  • Use BeginRequest/EndRequest to open/close the session. Handle the transaction with AOP – attributes. I am not sure but I think this is the case for the AutoTransaction facility of castle.
  • To use Asp.Net MVC ActionFilters to Open/Close the session and the transaction.

If you are in a web environment, please check for example this: session-per-web-global.cs. A snippet of that code:

public static ISessionFactory SessionFactory { get; private set; }
protected void Application_Start()
{
    ...     
    //Configure NHibernate and create a session factory for the application
    var nhibernateConiguration = new NHibernate.Cfg.Configuration();
    nhibernateConiguration.Configure();
    SessionFactory = nhibernateConiguration.BuildSessionFactory();
}

protected void Application_BeginRequest(object sender, EventArgs e)
{
    //Create NHibernate session for this request and bind it to the
    //NHibernate session context (configured as web context using HttpContext)
    var session = SessionFactory.OpenSession();
    NHibernate.Context.CurrentSessionContext.Bind(session);
}

protected void Application_EndRequest(object sender, EventArgs e)
{
    //Detach the session from this web request
    var session = NHibernate.Context.CurrentSessionContext.Unbind(SessionFactory);
    session.Dispose();
}

Even if not in the web-request scenario, try to find out some ways how to handle the ISession, and keep it open over more operations... check:

Building a Desktop To-Do Application with NHibernate

Radim Köhler
  • 122,561
  • 47
  • 239
  • 335