I'm working with JPA CriteriaBuilder, CriteriaQuery etc. and static metamodels for typesafe queries, like here for example: click.
I have 3 tables: Client, Package, Vegetable.
Every client has 1 or more packages, and those packages contain multiple vegetables.
What I have now:
CriteriaBuilder builder = entityManager.getCriteriaBuilder();
CriteriaQuery<Client> query = builder.createQuery(Client.class);
Root<Client> root = query.from(Client.class);
ListJoin<Package, Vegetable> join = root.join(Client_.packages).join(Package_.vegetables);
TypedQuery<Client> typedQuery = entityManager.createQuery(query);
return typedQuery.getResultList();
The ListJoin
I added recently. Point is what Hibernate does: generates the whole select for all fields in Client
class from the Client
table inner joined with Package
and Vegetable
, but it doesn't actually selects those fields from joined tables. It gets every package by ID and then every vegetable by ID, thus doing n+1
selects.
Without the ListJoin
it doesn't inner join those tables, but I'm working on it right now so I added those joins. Now I want to select all the fields from those classes so I get whole object hierarchy with 1 select. I tried doing something with projections like in the link I gave in Projecting the result
chaper, but I have no idea how to connect that with ListJoin
.
Is that even possible in this situation? When I run this query on database (with manually added all the fields from joined tables) it works fine, but would Hibernate handle that? And if so - how to project the result so it selects all the fields from 3 tables joined together and constructs whole object hierarchy, all with 1 select?
//Edit: managed to retrieve all packages with a single query, but going further raises exception:
Root<Client> root = query.from(Root.class);
ListJoin<Client, Package> join = root.join(Client_.packages);
ListJoin<Package, Vegetable> secondJoin = join.join(Package_.vegetables);
root.fetch(Client_.packages);
Naturally, I tried to add: join.fetch(Package_.vegetables);
but it raises the org.hibernate.QueryException: query specified join fetching, but the owner of the fetched association was not present in the select list
, no idea what is that.
As to the latest comment: gonna try that now.
//Edit2: I added 2 fetches (couldn't cast them to Join
like in that answer, compiler errors):
Fetch<Client, Package> join = root.fetch(Client_.packages);
Fetch<Package, Vegetable> secondJoin = join.fetch(Package_.vegetables);
It raises org.hibernate.loader.MultipleBagFetchException: cannot simultaneously fetch multiple bags
, known error I guess so at least got something to search for.
//Edit3: Changed it both to Sets and it works, thanks, couldn't have done it without the Fetch instead of Join
suggestion, seems kinda unintuitive to me.