J'aimerais avoir une collection d'objets enfants (ici exemple chat-chaton) qui sont commandés. Et gardez leur ordre sur l'ajout de nouveaux éléments.
@Entity
public class Cat {
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)
@OrderBy("name ASC")
private List<Kitten> kittens;
public void setKittens(List<Kitten> kittens) { this.kittens = kittens; }
public List<Kitten> getKittens() { return kittens; }
}
Quand je fais cat.getKittens.add(newKitten)
l'ordre par nom sera rompu.
Est-il possible de laisser hibernation faire le travail de garder la collection toujours commandée? En utilisant l'annotation @ Sort hibernate ?
@ Sort a l'inconvénient de vous obliger à implémenter une interface comparable ... Quelle serait la bonne façon de faire "JPA pur"? Tout sauvegarder dans DB et le recharger? Est-il logique de combiner @OrderBy et @Sort?
Mise à jour La solution jusqu'à présent consiste à combiner @OrderBy et @Sort. @OrderBy conduit à une clause ORDER BY
Dans le SQL généré qui est meilleure pour les performances (je suppose que Java est à nouveau "tri" lors de l'insertion dans le conteneur trié, mais cela devrait être beaucoup plus rapide car les éléments sont déjà triés) @Sort avec une interface Comparable
implémentée conduit à un conteneur toujours trié. Notez que j'utilise maintenant SortedSet
au lieu de List
. Voici le code mis à jour:
@Entity
public class Cat {
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)
@OrderBy("name ASC")
@Sort(type = SortType.NATURAL)
private SortedSet<Kitten> kittens;
public void setKittens(SortedSet<Kitten> kittens) { this.kittens = kittens; }
public SortedSet<Kitten> getKittens() { return kittens; }
}
Si vous souhaitez éviter les annotations non standard, vous pouvez faire en sorte que kittens
utilise une implémentation triée de Collection
. Cela garantirait que kittens
est toujours dans l'ordre trié. Quelque chose comme ça:
@Entity
public class Cat {
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)
@OrderBy("name ASC")
private SortedSet<Kitten> kittens = new TreeSet<>();
}
Notez que cette approche nécessite également Kitten
pour implémenter Comparable
(vous pouvez également passer un Comparator
à votre constructeur TreeSet
). De plus, j'utilise un Set
parce que je ne connais aucune implémentation standard triée de List
et je suppose que le Cat
n'a pas de clones dans sa portée = p.
pdate: Je ne sais pas à quel point Hibernate est difficile avec ses définitions getter/setter, mais avec EclipseLink, j'ai pu supprimer un setter entièrement et encapsuler le List
retourné par mon getter dans un appel Collections.unmodifiableList(...)
. J'ai ensuite défini des méthodes spéciales pour modifier la collection. Vous pouvez faire la même chose et forcer les appelants à utiliser une méthode add qui insère les éléments dans l'ordre trié. Si Hibernate se plaint de ne pas avoir le getter/setter, peut-être pourriez-vous changer le modificateur d'accès? Je suppose que cela dépend de jusqu'où vous êtes prêt à aller pour éviter les dépendances non standard.
La dernière version d'Hibernate utilise de nouvelles annotations pour ce faire:
@SortNatural
@OrderBy("name ASC")
private SortedSet<Kitten> kittens = new TreeSet<>();
Il y a deux parties à cela:
@OrderBy
Spécifie qu'une clause order by
Doit être ajoutée à la requête de base de données lors de la récupération des enregistrements associés.@SortNatural
Suppose que Kitten
implémente l'interface Comparable
et utilise ces informations lors de la construction de l'instance TreeSet
. Notez que vous pouvez remplacer cela par l'annotation @SortComparator
, Qui vous permet de spécifier une classe Comparator
qui sera transmise au constructeur TreeSet
.Voir la documentation: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#collections-sorted-set