Why does Hibernate Criteria generate a JOIN clause when using FetchType.EAGER


#1

Hi, I am currently migrating from 5.0 to 5.3.7
I checked a different behavior with CriteriaBuilder vs. Criteria and the EAGER annotation
In the following example

Criteria generates a sql query with an inner join on Address
CritriaBuilder no join
I do not understand why?
Thank you in advance for your assistance

@Entity
public class Person {
    @Id
    public Integer id;
    public String name;
    @ManyToOne(fetch = FetchType.EAGER)
	@JoinColumn(name = "id", nullable = false)
    public Address address;

    ... 
    getter and setter
}
@Entity
public class Address {
    @Id
    public Integer id;
    public String name;
    ... 
    getter and setter
}
// test with deprecated Criteria
Criteria crit = session.createCriteria(Person.class);
crit.add(Restrictions.eq("name","aname"));
List<Person> results = crit.list();

// sql result with deprecated Criteria
select person.*, address.* from person 
where person.name = 'aname'
inner join person.id = address.id

// test with CriteriaBuilder
CriteriaBuilder builder = session.getCriteriaBuilder();		
CriteriaQuery<Person> criteria = builder.createQuery(Person.class);			
Root<Person> root = criteria.from(Person.class);
criteria.where(builder.equal(root.get("name"), "aname"));
ession.createQuery(criteria).getResultList();
...
// sql result with CriteriaBuilder
select person.* from person 
where person.name = 'aname'

if I add

// CriteriaBuilder
root.fetch(name)

it’s ok but it is necessary to reconsider in this case the EAGER annotation


#2

First, this is not a valid SQL:

select person.*, address.* from person 
where person.name = 'aname'
inner join person.id = address.id

The JOIN comes before the WHERE clause and there is no ON clause either.

Second, Hibernate criteria should not generate that unless you JOIN the association.

The query you posted for Criteria API should be the same for legacy Criteria because, just like JPQL, the default fetch plan is overridden and a secondary query should be issued for the EAGER association.

Anyway, don’t use EAGER fetching. It’s very bad for performance and can easily lead to N+1 query issues.


#3

Thank you for your response

yes the SQL is like

select person.*, address.* from person 
inner join adress on person.id = address.id
where person.name = 'aname'

is it possible to have in this case an example with an annotation EAGER and a CriteriaBuilder


#4

With JPQL and Criteria API queries, if you want to JOIN fetch associations, you need to explicitly use the fetch. Annotations only count for direct fetching, when you are fetching the entity by its identifier.