web-dev-qa-db-fra.com

Comment faire pour rejoindre rejoindre chercher plusieurs enfants dans Hibernate?

Je travaille avec hibernate et j'ai des problèmes pour créer une requête hql qui récupère tous les enfants de mon objet.

Par exemple: L'utilisateur d'objet a une liste de voitures et une liste d'amis.

Pour obtenir un utilisateur avec ses voitures, j'utiliserais la requête suivante:

from User u left join fetch u.cars where u.id = ?

Cela fonctionne bien, alors j'ai pensé qu'il serait facile de trouver un utilisateur avec ses voitures et avec ses amis avec la requête suivante:

from User u left join fetch u.cars left join fetch u.friends where u.id = ?

Mais cela me donne l'erreur suivante:

HibernateException: impossible d'extraire simultanément plusieurs sacs

Ma question est la suivante: quelle est la bonne façon de récupérer plusieurs enfants en veille prolongée? 

16
Bjorn Rombaut

Au plus un des enfants de la collection doit être un sac (c'est-à-dire déclaré comme une liste). Déclarez les autres collections en tant qu'ensembles, et cela fonctionnera.

Attention, cependant, que de telles jointures fetch crée un produit cartesiann des lignes. Si les deux collections contiennent 100 éléments, une telle requête extrait 10 000 lignes de la base de données. Il est parfois plus efficace d'exécuter une première requête qui récupère une collection et une seconde qui récupère l'autre (ce qui réduit le nombre de lignes récupérées à 200). C'est aussi un moyen d'éviter le problème que vous avez:

select u from User u left join fetch u.cars where u.id = :id;
select u from User u left join fetch u.friends where u.id = :id;
12
JB Nizet

Vous venez de frapper le problème Collection/List (sac).

Voici un lien vers un "numéro" officiel d'Hibernate à ce sujet: https://hibernate.atlassian.net/browse/HHH-1718 . Comme vous pouvez le constater, il a été ouvert en 2006 et est toujours ouvert.

En plus des propositions de JB Nizet, je vous suggère d’utiliser Set (au lieu de Collection ou List) dans votre modèle (si vous le pouvez). Sinon, vous pouvez également spécifier votre Collection/List en tant que FetchMode.SUBSELECT et en dernière option (difficile à implémenter). ), vous pouvez utiliser @IndexColumn sur votre @ OneToMany/@ ManyToMany. 

Cet article de blog vous guidera dans la mise en œuvre de solutions: http://jroller.com/eyallupu/entry/hibernate_exception_simultaneous_fetch_multiple

En d'autres termes, il n'y a pas de solution pour faire exactement ce que vous voulez faire, à l'exception des solutions de contournement.

J'espère que cela t'aides!

Edit: typo

8
1lln3ss

Impossible, car il serait trop lourd pour l'application/la base de données. Vous devez créer 2 critères distincts et récupérer les données séparément.

Cat cat = sess.createCriteria(Cat.class)
              .add(Restrictions.like("name", "F%"))
              .uniqueResult();

List kitten = sess.createCriteria(Kitten.class)
                  .add(Restrictions.eq("cat", cat))
                  .createCriteria("kittens")
                  .add(Restrictions.like("name", "F%"))
                  .list();

List mate = sess.createCriteria(Mate.class)
                .add(Restrictions.eq("cat", cat))
                .createCriteria("mate")
                .add(Restrictions.like("name", "F%"))
                .list();
0
aishu