Keerthi
Keerthi

Reputation: 614

Eager fetching - find vs JPQL

I have a one-to-one relationship between two entities - Student and Address.

//Student

@OneToOne(fetch = EAGER)
@JoinColumn(name = "ADDRESS_ID")
private Address address;

Invoking entityManager.find(Student.class, 1) results in ADDRESS eagerly fetched as expected:

Hibernate: 
    select
        student0_.id as id1_4_0_,
        student0_.address_id as address_7_4_0_,
        student0_.crt_ts as crt_ts2_4_0_,
        student0_.email as email3_4_0_,
        student0_.first_name as first_na4_4_0_,
        student0_.last_name as last_nam5_4_0_,
        student0_.upd_ts as upd_ts6_4_0_,
        address1_.id as id1_1_1_,
        address1_.city as city2_1_1_,
        address1_.state as state3_1_1_,
        address1_.street as street4_1_1_,
        address1_.zip as zip5_1_1_ 
    from
        t_student student0_ 
    left outer join
        t_address address1_ 
            on student0_.address_id=address1_.id 
    where
        student0_.id=1

But, invoking

String query = "select s from Student s where s.id=1";
return entityManager.createQuery(query, Student.class).getSingleResult();

does not trigger eager fetching of ADDRESS:

Hibernate: 
    select
        student0_.id as id1_4_,
        student0_.address_id as address_7_4_,
        student0_.crt_ts as crt_ts2_4_,
        student0_.email as email3_4_,
        student0_.first_name as first_na4_4_,
        student0_.last_name as last_nam5_4_,
        student0_.upd_ts as upd_ts6_4_ 
    from
        t_student student0_
    where
        student0_.id=1

Why is this discrepancy happening?

Upvotes: 1

Views: 484

Answers (1)

SternK
SternK

Reputation: 13111

The behavior that you see described in the documentation.

If you are using an entity query that does not contain a JOIN FETCH directive Hibernate uses a secondary select.

This is because the entity query fetch policy cannot be overridden, so Hibernate requires a secondary select to ensure that the EAGER association is fetched prior to returning the result to the user.

If you forget to JOIN FETCH all EAGER associations, Hibernate is going to issue a secondary select for each and every one of those which, in turn, can lead to N+1 query issues.

For this reason, you should prefer LAZY associations.

So, you can fix your query in the following way:

entityManager.createQuery(
  "select s from Student s left join fetch s.address where s.id = :id",
   Student.class
)
.setParameter("id", id)
.getSingleResult()

Upvotes: 1

Related Questions