What is the difference between JOIN and JOIN FETCH when using JPA and Hibernate

256,409

Solution 1

In this two queries, you are using JOIN to query all employees that have at least one department associated.

But, the difference is: in the first query you are returning only the Employes for the Hibernate. In the second query, you are returning the Employes and all Departments associated.

So, if you use the second query, you will not need to do a new query to hit the database again to see the Departments of each Employee.

You can use the second query when you are sure that you will need the Department of each Employee. If you not need the Department, use the first query.

I recomend read this link if you need to apply some WHERE condition (what you probably will need): How to properly express JPQL "join fetch" with "where" clause as JPA 2 CriteriaQuery?

Update

If you don't use fetch and the Departments continue to be returned, is because your mapping between Employee and Department (a @OneToMany) are setted with FetchType.EAGER. In this case, any HQL (with fetch or not) query with FROM Employee will bring all Departments. Remember that all mapping *ToOne (@ManyToOne and @OneToOne) are EAGER by default.

Solution 2

in this link i mentioned before on the comment, read this part :

A "fetch" join allows associations or collections of values to be initialized along with their parent objects using a single select. This is particularly useful in the case of a collection. It effectively overrides the outer join and lazy declarations of the mapping file for associations and collections.

this "JOIN FETCH" will have it's effect if you have (fetch = FetchType.LAZY) property for a collection inside entity(example bellow).

And it is only effect the method of "when the query should happen". And you must also know this:

hibernate have two orthogonal notions : when is the association fetched and how is it fetched. It is important that you do not confuse them. We use fetch to tune performance. We can use lazy to define a contract for what data is always available in any detached instance of a particular class.

when is the association fetched --> your "FETCH" type

how is it fetched --> Join/select/Subselect/Batch

In your case, FETCH will only have it's effect if you have department as a set inside Employee, something like this in the entity:

@OneToMany(fetch = FetchType.LAZY)
private Set<Department> department;

when you use

FROM Employee emp
JOIN FETCH emp.department dep

you will get emp and emp.dep. when you didnt use fetch you can still get emp.dep but hibernate will process another select to the database to get that set of department.

so its just a matter of performance tuning, about you want to get all result(you need it or not) in a single query(eager fetching), or you want to query it latter when you need it(lazy fetching).

Use eager fetching when you need to get small data with one select(one big query). Or use lazy fetching to query what you need latter(many smaller query).

use fetch when :

  • no large unneeded collection/set inside that entity you about to get

  • communication from application server to database server too far and need long time

  • you may need that collection latter when you don't have the access to it(outside of the transactional method/class)

Solution 3

JOIN

When using JOIN against an entity associations, JPA will generate a JOIN between the parent entity and the child entity tables in the generated SQL statement.

So, taking your example, when executing this JPQL query:

FROM Employee emp
JOIN emp.department dep

Hibernate is going to generate the following SQL statement:

SELECT emp.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id

Note that the SQL SELECT clause contains only the employee table columns, and not the department ones. To fetch the department table columns, we need to use JOIN FETCH instead of JOIN.

JOIN FETCH

So, compared to JOIN, the JOIN FETCH allows you to project the joining table columns in the SELECT clause of the generated SQL statement.

So, in your example, when executing this JPQL query:

FROM Employee emp
JOIN FETCH emp.department dep

Hibernate is going to generate the following SQL statement:

SELECT emp.*, dept.*
FROM employee emp
JOIN department dep ON emp.department_id = dep.id

Note that, this time, the department table columns are selected as well, not just the ones associated with the entity listed in the FROM JPQL clause.

Also, JOIN FETCH is a great way to address the LazyInitializationException when using Hibernate as you can initialize entity associations using the FetchType.LAZY fetching strategy along with the main entity you are fetching.

Solution 4

If you have @oneToOne mapping set to FetchType.LAZY and you use second query (because you need Department objects to be loaded as part of Employee objects) what Hibernate will do is, it will issue queries to fetch Department objects for every individual Employee object it fetches from DB.

Later, in the code you might access Department objects via Employee to Department single-valued association and Hibernate will not issue any query to fetch Department object for the given Employee.

Remember, Hibernate still issues queries equal to the number of Employees it has fetched. Hibernate will issue same number of queries in both above queries, if you wish to access Department objects of all Employee objects

Solution 5

Dherik : I'm not sure about what you say, when you don't use fetch the result will be of type : List<Object[ ]> which means a list of Object tables and not a list of Employee.

Object[0] refers an Employee entity 
Object[1] refers a Departement entity 

When you use fetch, there is just one select and the result is the list of Employee List<Employee> containing the list of departements. It overrides the lazy declaration of the entity.

Share:
256,409

Related videos on Youtube

abbas
Author by

abbas

A Java EE and Semantic Web Engineer.

Updated on July 14, 2022

Comments

  • abbas
    abbas almost 2 years

    Please help me understand where to use a regular JOIN and where a JOIN FETCH. For example, if we have these two queries

    FROM Employee emp
    JOIN emp.department dep
    

    and

    FROM Employee emp
    JOIN FETCH emp.department dep
    

    Is there any difference between them? If yes, which one to use when?

    • Angga
      Angga almost 11 years
      you can find it here link read 14.3. Associations and joins
    • abbas
      abbas almost 11 years
      I have gone through that documententation but still don't know where should I use a JOIN and where a JOIN FETCH.
    • Bunti
      Bunti over 8 years
      If you have @oneToOne mapping set to FetchType.LAZY and you use second query(because you need Department objects to be loaded as part of Employee objects) what Hibernate will do is, it will issue queries to fetch Department objects for every individual Employee object it fetches from DB. Later in the code you might access Department objects via Employee to Department single-valued association and Hibernate will not issue any query to fetch Department object for the given Employee. Remember Hibernate still issues queries equal to the number of Employees it has fetched.
    • Edward J Beckett
      Edward J Beckett over 7 years
      To assist in the doc hunt ~ Fetching Strategies
    • Shameera Anuranga
      Shameera Anuranga over 4 years
      how to handle if there was no data in department table
    • abbas
      abbas over 4 years
      @ShameeraAnuranga I think in that case you will need a LEFT OUTER JOIN.
  • abbas
    abbas almost 11 years
    Could you explain it for the queries that I just wrote in the updated question.
  • Dherik
    Dherik about 9 years
    I don't know if I understand your concern. If you don't use fetch, your query will return only the Employees. If the Departments, even in this case, continue to be returned, is because your mapping between Employee and Department (a @OneToMany) are setted with FetchType.EAGER. In this case, any HQL (with fetch or not) query with FROM Employee will bring all Departments.
  • Bilal BBB
    Bilal BBB about 9 years
    Without using fetch (join term only), the result would be an array of collections, two rows, the first is a collection of Employees and the second is a collection of Departments. Using eager fetch or lazy fetch, departments will be fetched.
  • Dherik
    Dherik about 9 years
    Without fetch on HQL, this will happen only if your mapping between Employee and Department are EAGER (@OneToMany(fetch = FetchType.EAGER). If is not the case, the Departments will not be returned.
  • Bilal BBB
    Bilal BBB about 9 years
    @Dherik try it yourself, You'll get a ClassCastException.
  • gstackoverflow
    gstackoverflow over 8 years
    Which behaviour will be if we execute statement without fetch and get result. Then within session we will treat to department?
  • Dherik
    Dherik over 8 years
    I figure out the problem. Is not a fetch problem, but how the select was made in the HQL. Try SELECT emp FROM Employee emp JOIN FETCH emp.department dep. JPA/Hibernate have this behaviour of return a List of Object[] when you ommit the SELECT part.
  • Dherik
    Dherik over 8 years
    @gstackoverflow, yes
  • Divs
    Divs over 6 years
    useful consideration : "no large unneeded collection/set inside that entity you about to get"
  • Stephane
    Stephane almost 6 years
    Would the departments still be eagerly fetched if the departments inside the employee was a List instead of a Set ?
  • Stephane
    Stephane almost 6 years
    Does using the FETCH keyword in an JPQL statement imply an eagerly retrieved property ?
  • D B
    D B over 4 years
    I use native query with Lazy fetch in both sides of relationship but still loads hierarchy of child relations.
  • A.Onur Özcan
    A.Onur Özcan over 4 years
    Is it possible to use multiple JOIN FETCH in same query?
  • long
    long about 4 years
    Worth mention that fetch has to be used if (using our example) you want to order by some Department attribute. Otherwise, (valid at least for PG) you might get ERROR: for SELECT DISTINCT, ORDER BY expressions must appear in select list
  • Vlad Mihalcea
    Vlad Mihalcea almost 3 years
    Yes, it's possible for any number of @ManyToOne and @OneToOne associations and at most one collection.
  • Robs
    Robs about 2 years
    @Dherik Is there a way to use this query but with nativeQuery=true?
  • Dherik
    Dherik almost 2 years
    @Robs If you use nativeQuery you are not anymore using the JPQL/HQL language to create queries; you are using plain SQL. So, the fetch is not available.