I would like to have a collection of child objects (here cat-kitten example) that are ordered. And keep their order on adding of new elements.
@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; }
}
When I do cat.getKittens.add(newKitten)
the order by name will be broken.
Is it possible to let hibernate do the work of keeping the collection always ordered? By using the @Sort hibernate annotation?
@Sort has the disadvantage that it forces you to implement Comparable interface ...
What would be the right 'pure JPA' way to do that? Saving everything to DB and reloading it?
Makes it sense to combine @OrderBy and @Sort?
Update
Solution up to now is to combine @OrderBy and @Sort. @OrderBy leads to a ORDER BY
clause in the generated SQL which is better for performance (I assume that java is "sorting" again on inserting into the sorted container, but that should be much faster because the elements are already sorted)
@Sort together with an implemented Comparable
interface leads to a always sorted container. Note that I use now SortedSet
instead of List
. Here the updated Code:
@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; }
}
If you want to avoid non-standard annotations, you could make
kittens
use some sortedCollection
implementation. This would ensure thatkittens
is always in sorted order. Something like this:Note that this approach also requires
Kitten
to implementComparable
(alternatively, you could pass aComparator
to yourTreeSet
constructor). Also, I'm using aSet
because I'm not aware of any standard sortedList
implementation and I'm assuming theCat
does not have any clones in its litter =p.Update: I'm not sure how picky Hibernate is with its getter/setter definitions, but with EclipseLink I've been able to remove a setter entirely and wrap the
List
returned by my getter in aCollections.unmodifiableList(...)
call. I then defined special methods for modifying the collection. You could do the same thing and force callers to use an add method that inserts elements in sorted order. If Hibernate complains about not having the getter/setter, maybe you could change the access modifier? I guess it comes down to how far you're willing to go to avoid non standard dependencies.The latest version of Hibernate uses new annotations to accomplish this:
There are two parts to this:
@OrderBy
annotation specifies that anorder by
clause should be added to the database query when fetching the related records.@SortNatural
annotation assumes thatKitten
implements theComparable
interface and uses that information when constructing theTreeSet
instance. Note that you can replace this with the@SortComparator
annotation, which allows you to specify aComparator
class that will be passed to theTreeSet
constructor.See documentation: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#collections-sorted-set
No need to write
Make Sure Kitten Class implements Comparable interface properly.