56 votes

Alternatives de l'Union d'Hibernate

Quelles sont les alternatives pour implémenter une requête d'union avec hibernate? Je sais que hibernate ne prend pas en charge les requêtes des syndicats pour le moment. Pour le moment, la seule façon de créer un syndicat consiste à utiliser un tableau d'affichage.

L'autre option consiste à utiliser plain jdbc, mais de cette façon, je perdrais tous mes goodies, ainsi que la validation du mappage hibernate effectuée par hibernate par rapport aux tables / colonnes.

67voto

sfussenegger Points 16204

Vous pouvez utiliser id in (select id from ...) or id in (select id from ...)

par exemple, au lieu de non-travail

from Person p where p.name="Joe"
union
from Person p join p.children c where c.name="Joe"

vous pourriez faire

from Person p 
  where p.id in (select p1.id from Person p1 where p1.name="Joe") 
    or p.id in (select p2.id from Person p2 join p2.children c where c.name="Joe");

Au moins l'utilisation de MySQL, vous serez confronté à des problèmes de performances avec la suite. Il est parfois plus facile de faire un pauvre homme jointure sur deux requêtes à la place:

// use set for uniqueness
Set<Person> people = new HashSet<Person>((List<Person>) query1.list());
people.addAll((List<Person>) query2.list());
return new ArrayList<Person>(people);

Il est souvent préférable de faire deux requêtes simples que d'un seul complexe.

EDIT:

pour donner un exemple, voici les EXPLIQUER de sortie de la requête MySQL à partir de la sous-sélection de la solution:

mysql> explain 
  select p.* from PERSON p 
    where p.id in (select p1.id from PERSON p1 where p1.name = "Joe") 
      or p.id in (select p2.id from PERSON p2 
        join CHILDREN c on p2.id = c.parent where c.name="Joe") \G
*************************** 1. row ***************************
           id: 1
  select_type: PRIMARY
        table: a
         type: ALL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: 247554
        Extra: Using where
*************************** 2. row ***************************
           id: 3
  select_type: DEPENDENT SUBQUERY
        table: NULL
         type: NULL
possible_keys: NULL
          key: NULL
      key_len: NULL
          ref: NULL
         rows: NULL
        Extra: Impossible WHERE noticed after reading const tables
*************************** 3. row ***************************
           id: 2
  select_type: DEPENDENT SUBQUERY
        table: a1
         type: unique_subquery
possible_keys: PRIMARY,name,sortname
          key: PRIMARY
      key_len: 4
          ref: func
         rows: 1
        Extra: Using where
3 rows in set (0.00 sec)

Plus important encore, 1. ligne ne pas utiliser toute l'index et considère 200k+ lignes. Mauvais! L'exécution de cette requête a pris 0,7 s wheres les deux sous-requêtes sont en millisecondes.

30voto

Vladimir Dyuzhev Points 10647

Utilisez VIEW. Les mêmes classes peuvent être mappées sur différentes tables / vues en utilisant un nom complet, afin que vous n'ayez même pas beaucoup de duplication. Être là, ça fait, ça marche.

JDBC simple a un autre problème caché: il n'a pas connaissance du cache de session Hibernate. Par conséquent, si quelque chose est mis en cache jusqu'à la fin de la transaction et qu'il n'est pas vidé de la session Hib, la requête JDBC ne le trouvera pas. Pourrait être très déroutant parfois.

6voto

CodingWithSpike Points 17720

Je suis d'accord avec Vladimir. J'ai aussi regardé dans l'aide de l'UNION dans les requêtes HQL et ne pouvait pas trouver un moyen de contourner cela. La chose étrange est que j'ai pu trouver (dans les Hibernate FAQ) que l'UNION est pas pris en charge, les rapports de bogues concernant l'UNION marqué "fixe", les forums de gens qui disent que les déclarations seraient tronqués au niveau de l'UNION, et d'autres groupes de discussion de personnes déclarant qu'elle fonctionne très bien... Après une journée de coucher avec elle, j'ai fini le portage de mon HQL ordinaire, SQL, mais le faire dans une Vue dans la base de données serait une bonne option. Dans mon cas, les parties de la requête ont été générées de façon dynamique, j'ai donc dû construire le SQL dans le code à la place.

2voto

Walt Points 11

J'ai peut-être un problème plus simple à résoudre. Mon "par exemple" était dans JPA avec Hibernate en tant que fournisseur de JPA.

J'ai divisé les trois sélections (deux dans un deuxième cas) en sélections multiples et combiné les collections renvoyées moi-même, remplaçant ainsi un «syndicat tous».

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X