Hibernate change fetch mode in runtime

2019-03-16 12:32发布

问题:

I have two tables related together using one-to-many relation : employee -> department : and relation through department_id in the employee table.

I use hibernate : and my hibernate mapping files are:

<?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">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping default-lazy="false">
 <class catalog="moi"
  name="com.ebla.moi.correspondence.model.entity.user.User" table="user">
  <id name="id" type="java.lang.Long">
   <column name="id"/>
   <generator class="identity"/>
  </id>
  <many-to-one
   class="com.ebla.moi.correspondence.model.entity.department.Department"
   fetch="select" name="department">
   <column name="department_id"/>
  </many-to-one>
  <property generated="never" lazy="false" name="name" type="java.lang.String">
   <column length="128" name="name" not-null="true"/>
  </property>
  <property generated="never" lazy="false" name="email" type="java.lang.String">
   <column length="128" name="email" not-null="true" unique="true"/>
  </property>
  <property generated="never" lazy="false" name="maritalStatus" type="java.lang.Short">
   <column name="marital_status" not-null="true"/>
  </property>
  <property generated="never" lazy="false" name="hireDate" type="java.lang.String">
   <column length="64" name="hire_date"/>
  </property>
 </class>
</hibernate-mapping>

and the second mapping file is :

<?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">
<!-- 
    Mapping file autogenerated by MyEclipse Persistence Tools
-->
<hibernate-mapping default-lazy="false">
 <class catalog="moi"
  name="com.ebla.moi.correspondence.model.entity.department.Department" table="department">
  <id name="id" type="java.lang.Long">
   <column name="id"/>
   <generator class="identity"/>
  </id>
  <property generated="never" lazy="false" name="name" type="java.lang.String">
   <column length="256" name="name" unique="true"/>
  </property>
  <set inverse="true" name="users" sort="unsorted">
   <key>
    <column name="department_id"/>
   </key>
   <one-to-many class="com.ebla.moi.correspondence.model.entity.user.User"/>
  </set>
 </class>
</hibernate-mapping>

My problem is : sometimes i need to get the employee with his department, and other times i need only the employee information with out department information..... and the same thing with department with employee.... using the mapping file above the hibernate bring the department and it's users if i need the employee or not... how to define my needs to hibernate to fetch just what i need...

thank you

回答1:

You could map the relation as "lazy" and write two queries to get your datas:

  • The usual simple query to get your data ("lazy"). E.g. "select e from Employee e where ..."

  • The same query using "fetch join" to force Hibernate to fetch "childs". E.g. "select e from Employee left join fetch e.department where ..."

LLP, Andrea



回答2:

You can use ICriteria to fetch your Employee.

You can use the SetFetchMode method of the ICriteria to determine whether the Department should be fetched, or not:

This will make sure that the Department is not fetched:

ICriteria crit = theSession.CreateCriteria (typeof(Employee));
crit.SetFetchMode ("Department", FetchMode.Lazy)

With this code, the department will be fetched.

ICriteria crit = theSession.CreateCriteria (typeof(Employee));
crit.SetFetchMode ("Department", FetchMode.Join)

Some say that it is best-practice to use the default fetchmode in the mappings (which would be lazy, i guess), and specify the fetch-mode in every specific scenario. (That is, in your repositories).



回答3:

One way of doing this is to have two classes representing an employee:

  • Employee which has department information mapped through;
  • EmployeeSummary which only has the employee data itself.

Both classes then have independent bindings onto the employee table, but only Employee also has the relationship onto department defined.

Then when you need all the information you load Employee instances, and when you just need employee information you load EmployeeSummary instances.

You can remove any duplication of ORM bindings and business logic by introducing a common superclass like AbstractEmployee to both of the employee classes.



回答4:

I think what you are looking for is fetch profiles . Also have a look over this example : http://arjan-tijms.omnifaces.org/2012/04/fetching-arbitrary-object-graphs-in-jpa.html