Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JPA/hibernate sorted collection @OrderBy vs @Sort

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; }  } 
like image 265
adler Avatar asked Nov 09 '13 02:11

adler


People also ask

What is difference between sorted collection and ordered collection which one is better?

An ordered collection means that the elements of the collection have a specific order. The order is independent of the value. A List is an example. A sorted collection means that not only does the collection have order, but the order depends on the value of the element.

What is difference between sorted and ordered collection in Hibernate?

When use sorting, Hibernate will load the associated Book entities from the database and use a Java Comparator to sort them in memory. That is not a good approach for huge Sets of entities. Ordering uses an ORDER BY clause in the SQL statement to retrieve the entities in the defined order.

How do you write orderBy in JPA?

With JPA Criteria – the orderBy method is a “one stop” alternative to set all sorting parameters: both the order direction and the attributes to sort by can be set. Following is the method's API: orderBy(CriteriaBuilder. asc): Sorts in ascending order.

How do you sort data in Hibernate?

The Order class has two methods to set the sorting order: asc(String attribute) : Sorts the query by attribute in ascending order. desc(String attribute) : Sorts the query by attribute in descending order.


2 Answers

If you want to avoid non-standard annotations, you could make kittens use some sorted Collection implementation. This would ensure that kittens is always in sorted order. Something like this:

@Entity  public class Cat {   @OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)   @OrderBy("name ASC")   private SortedSet<Kitten> kittens = new TreeSet<>(); } 

Note that this approach also requires Kitten to implement Comparable (alternatively, you could pass a Comparator to your TreeSet constructor). Also, I'm using a Set because I'm not aware of any standard sorted List implementation and I'm assuming the Cat 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 a Collections.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.

like image 103
DannyMo Avatar answered Oct 11 '22 15:10

DannyMo


The latest version of Hibernate uses new annotations to accomplish this:

@SortNatural @OrderBy("name ASC") private SortedSet<Kitten> kittens = new TreeSet<>(); 

There are two parts to this:

  1. The @OrderBy annotation specifies that an order by clause should be added to the database query when fetching the related records.
  2. The @SortNatural annotation assumes that Kitten implements the Comparable interface and uses that information when constructing the TreeSet instance. Note that you can replace this with the @SortComparator annotation, which allows you to specify a Comparator class that will be passed to the TreeSet constructor.

See documentation: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#collections-sorted-set

like image 37
mark.monteiro Avatar answered Oct 11 '22 13:10

mark.monteiro