5 votes

Ordonner des relations multiples de type one-to-many

J'ai un écran de recherche, utilisant JSF, JBoss Seam, et Hibernate en dessous. Il y a des colonnes pour A , B y C où les relations sont les suivantes :

A (1< --; >*) B (1< --; >*) C

Disons que A a un List< B > y B a un List< C > (les deux relations sont de type one-to-many).

La table de l'interface utilisateur peut être ordonnée par n'importe quelle colonne (ASC ou DESC). Je souhaite donc que les résultats de la requête soient ordonnés. C'est la raison pour laquelle j'ai utilisé des listes dans le modèle.

Cependant, j'ai reçu une exception indiquant qu'Hibernate ne peut pas récupérer rapidement plusieurs sacs (il considère les deux listes comme des sacs). Il existe un article de blog intéressant ici et ils identifient les solutions suivantes :

  1. Utiliser l'annotation @IndexColumn` (il n'y en a pas dans ma BD, et de plus, je veux que la position des résultats soit déterminée par l'ordonnancement, pas par une colonne d'index)
  2. Récupération paresseuse (pour des raisons de performance, j'ai besoin d'une récupération rapide).
  3. Changer la liste en set

J'ai changé la Liste en Set, ce qui est d'ailleurs plus correct, du point de vue du modèle.

  • Tout d'abord, si l'on n'utilise pas @OrderBy, l'option PersistentSet renvoyée par Hibernate englobe un HashSet qui n'a pas d'ordre. Ainsi, lorsque je l'itère dans l'interface utilisateur, l'ordre est aléatoire, quel que soit l'ordre utilisé par la base de données.
  • Deuxièmement, si je hacer utiliser @OrderBy, le PersistentSet enveloppe un LinkedHashSet qui a commandé, et c'est ce que je voudrais. Cependant le OrderBy est codée en dur et a la priorité sur l'ordre que j'ai défini en utilisant Collections ( lien ) ou HQL ( lien ). Ainsi, toutes les autres commandes que je demande par l'intermédiaire de l'interface utilisateur viennent après celle-ci.

J'ai réessayé avec Sets et utilisé SortedSet (et sa mise en œuvre, TreeSet ), mais j'ai quelques problèmes :

  1. Je veux que l'ordonnancement ait lieu dans la base de données, et non en mémoire, ce qui est le cas. TreeSet (soit par le biais d'un comparateur, soit par l'interface Comparable des éléments).

  2. J'ai découvert qu'il existe l'annotation @Sort d'Hibernate, qui comporte une fonction SortOrder.UNSORTED et vous pouvez également définir un comparateur. Je n'ai toujours pas réussi à le faire compiler, mais je ne suis toujours pas convaincu que c'est ce dont j'ai besoin.

L'une des exigences est que le tri s'effectue dans la BD.

Création d'un projet Maven simple et engagement en tant que Code Google projet. C'est mon terrain de jeu personnel pour le problème.

3voto

Péter Török Points 72981

Quel est l'intérêt d'ordonner dans la base de données quand le même ensemble de résultats peut être réordonné par n'importe quelle colonne ? Si vous devez interroger la base de données à chaque fois qu'une colonne différente est cliquée sur l'interface utilisateur, vous créez un problème de performance. C'est exactement dans ce cas qu'il est judicieux d'ordonner l'ensemble en mémoire.

En ce qui concerne les sacs et les listes, voici ce qu'en dit le livre Hibernate :

Les sacs ne peuvent pas être triés (il n'y a pas d'obligation de trier les sacs). TreeBag malheureusement), pas plus que les listes ; l'ordre l'ordre des éléments d'une liste est défini par l'indice de la liste.

0voto

Arthur Ronald Points 19001

Sur la base de ce que Hibernate in Action a dit et de la solution de contournement fournie par votre propre réponse, vous pourriez trier votre collection au moment de l'exécution pour éviter votre exception

@Entity
public class Aa {

     private List<Bb> bbList - new ArrayList<Bb>();

     @OneToMany
     public List<Bb> getBbList() {
         return bbList;
     }

     @Transient
     public List<Bb> getBbListSortedBySomeProperty() {
         Collections.sort(bbList, new Comparator<Bb>() {
             public int compare(Bb o1, Bb o2) {
                 return o1.getSomeProperty().compareTo(o2.getSomeProperty());
             }
         });

         return bbList;

     }

}

Sachez que someProperty doit implémenter Comparable

...

@Entity
public class Bb {

     private List<Cc> ccList - new ArrayList<Cc>();

     @OneToMany
     public List<Cc> getCcList() {
         return ccList;
     }

}

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