1

I am trying to fetch data from database using hibernate annotation but it is not working as my expected. I have a two table Employee and Department. the java code is as below :

Employee class

 @Entity
    @Table(name = "EMPLOYEE")        
    public class EmployeeBO {

        @Id
        @GeneratedValue(strategy=GenerationType.IDENTITY)
        @Column(name = "EMPID")
        private int empId;
        @Column(name = "EMPNAME")
        private String empName;
        @Column(name = "SALARY")
        private int empSalary;
        @Column(name = "EMPADDRESS")
        private String empAddress;
        @Column(name = "EMPAGE")
        private int empAge;
        @Column(name = "DEPTID")
        private Integer deptId; 
        @ManyToOne(fetch=FetchType.EAGER)
        @JoinColumn(name="DEPTID", nullable = true, insertable = false, updatable = false)
        private DepartmentBO departmentBO;
// getter and setter 
    }

Department class :

@Entity
@Table(name = "DEPARTMENT")
public class DepartmentBO {

    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    @Column(name = "DEPTID")
    private int deptid;

    @Column(name = "DEPTNAME")
    private String deptName;
   // getter and setter.
}

spring-servlet.xml file :

<?xml version="1.0" encoding="UTF-8"?>
<!--?xml  version="1.0" encoding="UTF-8"?-->
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd 
    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd 
    http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.0.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">


    <context:annotation-config></context:annotation-config>

    <context:component-scan base-package="com.web"></context:component-scan>

    <context:property-placeholder location="file:D:/EasyProp/db.properties" ignore-unresolvable="false"/>

    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
        <property name="prefix" value="/WEB-INF/jsp/" />  
        <property name="suffix" value=".jsp" />  
    </bean>

    <bean id="basicDataSource" 
         class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"> 

        <property name="driverClassName" value="${driver.classname}" />
        <property name="url" value="${driver.url}" />
        <property name="username" value="${username}" />
        <property name="password" value="${password}" />
<!--        <property name="initialSize" value="10"/> -->
<!--         <property name="maxActive"  value="25"/> -->
<!--         <property name="maxIdle" value="25"/>   -->
        <!-- <aop:scoped-proxy/> -->
    </bean> 
    <tx:annotation-driven />
    <bean id="transactionManager"
        class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory" ref="mySessionFactory" />
    </bean>

    <!-- <bean id="dbUtil" class="com.web.utility.OnLoadStartUp" init-method="initialize">
        <property name="dataSource" ref="basicDataSource" />
    </bean> -->

    <!-- <bean id="loadOnStartUp" class="com.web.utility.LoadOnStartUp">
        <property name="baseService" ref="baseService"></property>
    </bean> -->

    <bean id="mySessionFactory"
        class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
        <property name="dataSource" ref="basicDataSource" />
        <property name="annotatedClasses">
            <list>
                <value>com.web.bo.EmployeeBO</value>
                <value>com.web.bo.DepartmentBO</value>  
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.hmb2ddl.auto">validate</prop>
                <prop key="hibernate.generate_statistics">true</prop>
                <prop key="hibernate.jdbc.fetch_size">10</prop>
                <prop key="hibernate.jdbc.batch_size">25</prop>
                <prop key="hibernate.jdbc.batch_versioned_data">true</prop>
                <prop key="hibernate.max_fetch_depth">3</prop>
                <prop key="hibernate.default_batch_fetch_size">8</prop>
                <prop key="hibernate.order_updates">true</prop>
                <prop key="hibernate.connection.release_mode">on_close</prop>
                <prop key="hibernate.bytecode.use_reflection_optimizer">true</prop>
                <prop key="hibernate.bytecode.provider">javassist</prop>                
            </props>
        </property>
    </bean>
</beans>

when i trying to fetch all data from employee and department table but it only returns the data from employee table my code for hit hql query as below :

List<EmployeeBO> empList = null; 
        empList = sessionFactory.getCurrentSession().createQuery("From "+employeeBO.getClass().getName()).list();   

above query is hit as below on database.

select employeebo0_.EMPID as EMPID0_, employeebo0_.DEPTID as DEPTID0_, employeebo0_.EMPADDRESS as EMPADDRESS0_, employeebo0_.EMPAGE as EMPAGE0_, employeebo0_.EMPNAME as EMPNAME0_, employeebo0_.SALARY as SALARY0_ from EMPLOYEE employeebo0_

But i want all data of the employee table and department table using Eager fetching.

Keval Trivedi
  • 1,290
  • 2
  • 13
  • 29
  • 2
    So, you don't want lazy fetching, but eager fetching, right? Lazy fetching consists precisely in NOT fetching the department information until you need it. – JB Nizet Apr 09 '15 at 09:42

4 Answers4

2

It works as expected. The EmployeeBO contains a DepartmentBO. The DepartmentBO will automatically be filled the moment you access it.

This is not true, if the Hibernate session containing the EmployeeBO has ended. Then the EmployeeBO is transient and hibernate will not fetch the missing object.

To enforce filling the DepartmentBO, you can add a fetch clause to your hql code. But that is not lazy fetching any more.

The HQL

from EmployeeBO join fetch EmployeeBO.department 

should do the job (replace the EmployeeBO with the actual entity name).

See here in the hibernate docs: https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/queryhql.html and for the fetching strategies here https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/performance.html#performance-fetching

From the comments, you actually want eager fetching on the relationship, so you need to declare the fetchtype to be eager:

@ManyToOne(fetch=FetchType.EAGER)

should fix it. Adding another doc here: https://docs.oracle.com/javaee/6/api/javax/persistence/ManyToOne.html

thst
  • 4,592
  • 1
  • 26
  • 40
  • Yes i know that DepartmentBO will automatically fill but it is not filled when i hit query. can you please explain your second point about session. – Keval Trivedi Apr 09 '15 at 09:50
  • Lazy fetching is exactly that: You fetch only what you have explicitly asked for. Any adjacent structure is fetched the moment you need it. What you want (a fully filled structure with one SQL) is called eager fetching. – thst Apr 09 '15 at 09:52
  • Hibernate works with proxy objects that contain the actual data and manage loading of missing parts. The proxy can only access any missing parts if it is inside a hibernate session. As soon as the session has ended, the proxy can only access the parts of the object that are already there. This is important if you send data to another thread for processing or manage the session yourself. See here for the hibernate object life cycle https://docs.jboss.org/hibernate/orm/3.3/reference/en/html/objectstate.html if you google this you will find tutorials en masse. – thst Apr 09 '15 at 09:57
  • 1
    I want fully filled structure with one sql – Keval Trivedi Apr 09 '15 at 10:00
  • Then you should annotate the many to one as eager. @ManyToOne(fetch=FetchType.EAGER, ...) – thst Apr 09 '15 at 10:02
  • can you please post the updated generated SQL and please update your question to explain that you want eager fetching, not lazy. – thst Apr 09 '15 at 13:11
  • Please visit to my updated question and share your view. – Keval Trivedi Apr 10 '15 at 06:48
  • does the query(sql) change, if you rewrite it with the fetch, as stated in my answer? – thst Apr 10 '15 at 07:26
  • 1
    it is working when i changed my hql query as per your suggestion but why it is not fill all structure when fetching only employee class details with the use of above query in question. – Keval Trivedi Apr 10 '15 at 09:36
  • I cannot tell why the query did not work as expected. Possibly because it is a query, not a direct fetch (load or get). Eager works in my Projects. – thst Apr 10 '15 at 11:34
0

There are two ways to do this: 1) use EAGER fetch type 2) call getDepartmentBO() on each employee after you get the employee

HJK
  • 1,382
  • 2
  • 9
  • 19
-1

I think you have missed the anotation for lazy loading.

You have to use (fetch=FetchType.LAZY) on a association which you want to lazy load

Ravi.Kumar
  • 761
  • 2
  • 12
  • 34
-1

Hibernate by default has Lazy loading. i.e. it would not fetch the data of another table. In you case if you want the data of department table, you will have to call getter of departmentBO if you are in hibernate session. Note: it will fire another query. else you can also use

Hibernate.initialize(entity.getdepartmentBO())

If you want by default to get the department data. use the following code

@ManyToOne(fetch=FetchType.EAGER)
Rahul Thachilath
  • 363
  • 3
  • 16