Search code examples
javahibernatehqlcriteria

A set of questions on Hibernate quering


Please help me with these Hibernate querying issues.

Consider the following structure:

@Entity
class Manager {
    @OneToMany
    List<Project> projects;
}

0) there are 2 possible ways of dynamic fetching in HQL:

  • select m from Manager m join m.projects
  • from Manager m join fetch m.projects

In my setup second one always returns a result of cartesian product with wrong number of objects in a list, while the first one always returns correct number of entities in a list. But the sql queries look the same. Does this mean that "select" clause removes redundant objects from the list in-memory? In this case its strange to see an advice in a book to use select distinct ... to get rid of redundant entities, while "select" does the job. If this is a wrong assumption than why these 2 queries return different results?

  1. If I utilize dynamic fetching by one of the 2 methods above I see a classic n+1 select problem output in my hibernate SQL log. Indeed, FetchMode annotations (subselect or join) do not have power while fetching dynamically. Do I really can't solve the n+1 problem in this particular case?

  2. Looks like Hibernate Criteria API does not support generics. Am I right? Looks like I have to use JPA Criteria API instead?

  3. Is it possible to write HQL query with an entity name parameter inside? For example "from :myEntityParam p where p.id=1" and call setParameter("myEntityParam", MyClass.class) after this. Actually what I want is generic HQL query to replace multiple non-generic dao's by one generic one.


Solution

  • 0) I always use a select clause, because it allows telling what you want to select, and is mandatory in JPQL anyway. If you want to select the managers with their projects, use

    select distinct m from Manager m left join fetch m.projects
    

    If you don't use the distinct keyword, the list will contain n instances of each manager (n being the number of projects of the manager): Hibernate returns as many elements as there are rows in the result set.

    1) If you want to avoid the n + 1 problem, fetch the other association in the same query:

    select distinct m from Manager m 
    left join fetch m.projects 
    left join fetch m.boss
    

    You may also configure batch fetching to load 10 bosses (for example) at a time when the first boss is accessed. Search for "batch fetching" in the reference doc.

    2) The whole Hibernate API is not generified. It's been made on JDK 1.4, before generics. That doesn't mean it isn't useful.

    3) No. HQL query parameters are, in the end, prepared statement parameters. You must use String concatenation to do this.