39

I have a userAccount entity mapped with a country entity . The country mapping in UserAccount class is like this

@ManyToOne(fetch=FetchType.EAGER)
@Fetch(FetchMode.JOIN)
@JoinColumn(name="f_country_id", nullable=true, insertable=false, updatable=false)
private Country country;

Even there is fetchmode defined as Join, hibernate fires a separate SQL Select to fetch countries.

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
Manish Mudgal
  • 1,166
  • 1
  • 9
  • 24
  • 1
    Did you solve this issue? How the accepted answer helped you? I'm facing the same problem, but the accepted answer doesn't help. – Giovanni Lovato Apr 22 '16 at 11:00
  • For eager its simple. Lazy will stop loading it. So answer is perfect here. Small catch is that when you have N to One relationship, it doesn't work. So we need to go with bytecode instrumentation and field properties modifier. Its a feature of hibernate though. – Manish Mudgal Apr 22 '16 at 11:29
  • The problem, as title and content suggest, is Hibernate issuing `SELECT` statements for a `@ManyToOne` relation with `EAGER` fetch type when the requested fetch mode is `JOIN`. The accepted answer states to remove the `fetch=FetchType.EAGER` from the annotation, an action that won't change anything since `EAGER` is the default fetch type for the annotation; even if you interpret the answer as "change `EAGER` with `LAZY`", that doesn't explain why Hibernate issues `SELECT` statements when it's instructed not to do so. – Giovanni Lovato Apr 22 '16 at 12:48

4 Answers4

17

Remove the fetch=FetchType.EAGER. Eager fetching triggers cascading select statements.

If you are using explicit HQL query e.g. "from User where something = someValue", Hibernate will not respect the annotated Fetch mode. You would need to specify the join in the HQL query or the fetch mode in the criteria.

techBeginner
  • 3,792
  • 11
  • 43
  • 59
Satadru Biswas
  • 1,555
  • 2
  • 13
  • 23
  • 3
    I need to have it eager. is there any way to fetch eager with join...? – Manish Mudgal Mar 28 '11 at 11:10
  • 1
    Stating the FetchMode.JOIN should do the trick. To get an eager loading, use either FetchType.EAGER or FetchMode.JOIN, use any one, using both is an over-kill. The former uses 'select' while the latter will use 'join'. – Satadru Biswas Mar 28 '11 at 11:15
  • 3
    Didn't solve the problem. It still firing the select statements to the database. I am using the following: @ManyToOne @Fetch(FetchMode.JOIN) @JoinColumn(name="f_country_id", nullable=true, insertable=false, updatable=false) private Country country; – Manish Mudgal Mar 29 '11 at 04:42
  • 1
    @Manish Mudgal : Are you using HQL to load the user object? – Satadru Biswas Mar 29 '11 at 05:50
  • 30
    If you are using explicit HQL query e.g. "from User where something = someValue", Hibernate will not respect the annotated Fetch mode. You would need to specify the join in the HQL query or the fetch mode in the criteria. – Satadru Biswas Mar 29 '11 at 06:20
  • 7
    Isn't FetchType.EAGER the default for ManyToOne? I think the explicit where clause as mentioned by @SatadruBiswas might be the problem. – James Selvakumar Jul 17 '12 at 04:13
  • 15
    Why was this answer accepted? In which way it resolve the OP issue? As @JamesSelvakumar stated, `FetchType.EAGER` is the default value for the annotation, so removing it won't change anything. – Giovanni Lovato Apr 22 '16 at 10:53
15

Satadru Biswas gave the answer in a previous comment .

Hibernate 3.x ignores the FetchMode annotation when you use the Query interface (Session.createQuery) so in this case you have to add an INNER JOIN FETCH clause to the FROM part of your query.

The criteria interface however will use this interface correctly.

sola
  • 1,498
  • 14
  • 23
11

I try use @Fetch(FetchMode.JOIN) hibernate adnotation in all api (JPQL and CriteriaBuilder) but didn't work. Only this code in service class work fine:

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<UserAccount > cq = cb.createQuery(UserAccount.class);
Root<UserAccount> o = cq.from(UserAccount.class);

o.fetch("country",JoinType.INNER);

em.createQuery(cq.select(o)).getResultList();
milosz
  • 650
  • 8
  • 14
0

I'm using the criteria query to fetch Customers.

public class PurchaseOrder
{
    .....
    .....      
    @ManyToOne(fetch=FetchType.EAGER, optional=true)
    @JoinColumn(name="ReportingCustomer_ID", nullable=true, insertable=false, updatable=false)
    @Fetch(FetchMode.JOIN)
    @NotFound(action=NotFoundAction.IGNORE)
    public ReportingCustomer getReportingCustomer()
    {
        return reportingCustomer;
    }
}

While getting PurchaseOrder it does a LEFT OUTER JOIN as below

select ... from PurchaseOrder this_ left outer join ReportingCustomer reportingc2_ 
on this_.ReportingCustomer_ID=reportingc2_.ReportingCustomer_ID
where ...
  1. When there is an entry in ReportingCustomer - It fires only the above query.
  2. When there is no entry for that record in ReportingCustomer - It fires a query for each PURCHASEORDER (m+1) queries.

I use "Progress" driver to connect to DB. I'm not sure why it fires m+1 queries only in scenario 2.

Ahmed Ashour
  • 5,179
  • 10
  • 35
  • 56
user3720735
  • 41
  • 1
  • 3
  • I'm experiencing the same issue: `FetchMode.JOIN` works since it finds one, then it starts with `SELECT`s. Did you find a solution? – Giovanni Lovato Apr 22 '16 at 10:47