13

Have following query to the database:

        Session session = EmployeesDAO.getSessionFactory().getCurrentSession();
        List<Employee> employees = new ArrayList<Employee>();
        try {
            session.beginTransaction();
            String hqlQuery = "from Employee emp "
                    + "left join fetch emp.employeesOffices employeesOffice "
                    + "left join fetch employeesOffice.office employeesOfficeOffice "
                    + "left join fetch employeesOfficeOffice.company "
                    + "left join fetch emp.address empAddress "
                    + "left join fetch empAddress.city empAddressCity "
                    + "left join fetch empAddressCity.country";
            Query empQuery = session.createQuery(hqlQuery);
            empQuery.setMaxResults(maxResult);
            employees = (List<Employee>) empQuery.list();
            session.getTransaction().commit();

        } catch (HibernateException e) {
            session.getTransaction().rollback();
            e.printStackTrace();
        }

While fetching employee.address.street, employee.address.houseNumber or employee.address.city it fails with the exception:

org.hibernate.LazyInitializationException: could not initialize proxy - no Session
    at org.hibernate.proxy.AbstractLazyInitializer.initialize(AbstractLazyInitializer.java:164)
    at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
    at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
    at com.employees.model.Address_$$_javassist_6.getCity(Address_$$_javassist_6.java)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
    at java.lang.reflect.Method.invoke(Unknown Source)
    at javax.el.BeanELResolver.getValue(BeanELResolver.java:87)
    at javax.el.CompositeELResolver.getValue(CompositeELResolver.java:67)
    at org.apache.el.parser.AstValue.getValue(AstValue.java:169)
    at org.apache.el.ValueExpressionImpl.getValue(ValueExpressionImpl.java:189)
    at org.apache.jasper.runtime.PageContextImpl.proprietaryEvaluate(PageContextImpl.java:985)
    at org.apache.jsp.WEB_002dINF.listEmployees_jsp._jspx_meth_c_005fout_005f3(listEmployees_jsp.java:306)
    at org.apache.jsp.WEB_002dINF.listEmployees_jsp._jspx_meth_c_005fforEach_005f1(listEmployees_jsp.java:248)
    at org.apache.jsp.WEB_002dINF.listEmployees_jsp._jspx_meth_c_005fforEach_005f0(listEmployees_jsp.java:155)
    at org.apache.jsp.WEB_002dINF.listEmployees_jsp._jspService(listEmployees_jsp.java:89)
    at org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:70)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:432)
    at org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:390)
    at org.apache.jasper.servlet.JspServlet.service(JspServlet.java:334)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.ApplicationDispatcher.invoke(ApplicationDispatcher.java:690)
    at org.apache.catalina.core.ApplicationDispatcher.processRequest(ApplicationDispatcher.java:477)
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:402)
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:329)
    at com.employees.controller.EmployeeController.processRequest(EmployeeController.java:69)
    at com.employees.controller.EmployeeController.doGet(EmployeeController.java:30)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:225)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:168)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:98)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:927)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1001)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:585)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)

Mapping for Employee:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.employees.model.Employee" table="employees">
        <id column="employee_id" name="employeeId" type="int">
            <generator class="sequence">
                <param name="sequence">EMP_SEQ</param>
            </generator>
        </id>
        <property column="first_name" name="firstName" type="java.lang.String" />
        <property column="last_name" name="lastName" type="java.lang.String" />

        <many-to-one name="address" column="address_id" 
            class="com.employees.model.Address"/>
        <set name="employeesOffices" >
            <key column="employee_id" />
            <one-to-many class="com.employees.model.EmployeeOffice"/>
        </set>

    </class>
</hibernate-mapping>

Mapping for Address:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.employees.model.Address" table="addresses">
        <id column="address_id" name="addressId" type="int">
            <generator class="sequence">
                <param name="sequence">ADDRESS_SEQ</param>
            </generator>
        </id>
        <property column="street" name="street" type="java.lang.String" />
        <property column="house_number" name="houseNumber" type="int" />
        <many-to-one name="city" column="city_id"
            class="com.employees.model.City"/>
    </class>

</hibernate-mapping>

It's absolutely normal with other classes (Office, Company, etc). If comment the lines which load address fields in jsp application works without any exceptions. What's wrong? By the way it shows all information on jsp despite the exception.

tiktak
  • 1,741
  • 2
  • 24
  • 44
  • off topic: I think it's better to specify package attribute in hibernate-mapping tag, after that you have no need to write full name of classes – Aleksei Bulgak Jan 26 '13 at 22:41

4 Answers4

36

Your objects inside employee are lazy initialized. That's mean, they are initializing only on demand on non-closed session. So you have to initialize them all manually inside loop after fetching from DB:

Query empQuery = session.createQuery(hqlQuery);
empQuery.setMaxResults(maxResult);
employees = (List<Employee>) empQuery.list();
for (Employee emp : employees) {
    Hibernate.initialize(emp.address);
}
Andremoniy
  • 31,241
  • 14
  • 110
  • 218
  • 5
    Then what's the point of lazy? Might as well change the semantics to do an eager fetch. – Rob Jan 26 '13 at 22:22
  • @Rob this is not always needed. Sometimes it is convenient to have lazy initialization, and initialize children only if it is needed. – Andremoniy Jan 26 '13 at 22:24
  • that's right, that's why my suggestion is that you get the scoping semantics right for each case. :) – Rob Jan 26 '13 at 22:25
  • Why are they `lazy` initialized? Why do `Office` and other associations work correctly? Is it wrong that `left join fetch` provides `eager` fetching? – tiktak Jan 26 '13 at 22:29
  • `for (Employee emp : employees) { Hibernate.initialize(emp.getAddress()); }` gives me `NullPointerException`. – tiktak Jan 26 '13 at 22:35
  • yes if you specify join fetch all data would be get immediately. look at this topic about fetch strategies http://www.mkyong.com/hibernate/hibernate-fetching-strategies-examples/ – Aleksei Bulgak Jan 26 '13 at 22:44
  • 1
    The point here is that you want the mapping to be lazy by default. This gives you the opportunity to load the data if you know you need it but not if you don't. If you need the data you need the data, you can't get away from that! You can use a join fetch or just access the property before closing the session but either way, you need that data so make sure you load it! – Alex Barnes Jan 27 '13 at 00:10
  • @tiktak add additionally check for `null` values: `... { if (emp != null) Hibernate.initialize(emp.getAddress()); } ...`. It this will not help, then post here full stack trace of this `NPE` exception. – Andremoniy Jan 27 '13 at 06:30
  • Thanks a lot, @Alex and @Andremoniy! You really help me to understand and solve this problem! I'll update my question with the code. – tiktak Jan 27 '13 at 18:30
16

Sinche Hibernate 4.2 you can use

.setProperty("hibernate.enable_lazy_load_no_trans", "true");

this option solves the dreaded

org.hibernate.LazyInitializationException: could not initialize proxy -
no Session

which took so many hours of life to programmers away.

saimiris_devel
  • 627
  • 1
  • 6
  • 16
9

Has nothing to do with the mapping. When you provide for lazy loading on an object, you accept a responsibility that has bewitched the ORM world for a decade: that the session you loaded the object with will be the same one as the session that is present when the lazy requests are issued.

In your case, it looks like the session is completely gone.

You have to have some means of either maintaining the session (which often leads to a need for conversation scope, which would mean either Seam or CDI (in EE 6)) or you have to resync your object with the new session that you have (usually by looking it up again).

Rob
  • 10,529
  • 6
  • 34
  • 54
2

add laze=false into <class name="com.employees.model.Employee" table="employees"> or you can init your object in Hibernate.init(Object) when you get object from db

Aleksei Bulgak
  • 5,541
  • 7
  • 39
  • 68