简体   繁体   中英

Hibernate many to one eager fetching not working

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.

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

有两种方法可以执行此操作:1)使用EAGER访存类型2)在获得雇员后,在每个雇员上调用getDepartmentBO()

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

Hibernate by default has Lazy loading. ie 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)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM