Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Hibernate: ordering a Set

I have a class Person who has a set of Books. It is not meaningful in the particular case to have an ordered or sorted collection.

Say now that I have a search page with a table showing the join of Person and Book. I want to be able to sort the results by fields from both Person AND Book, and then get a List from Hibernate, and iterate over it.

Because the collection is a Set, the ordering of the Books has vanished (PersistentSet of Hibernate wraps a HashSet of Books, which is not ordered).

So, with this approach I cannot have results also ordered by Book fields.

If I change the collection from Set to List, my model is semantically incorrect. There is no meaning for keeping order in the model.

Is there an approach to keep the ordering of Books? Perhaps there is a way for the PersistentSet to wrap a LinkedHashSet (which is ordered), where the order is defined by my search Criteria?

Cheers!

like image 620
Markos Fragkakis Avatar asked Apr 01 '10 13:04

Markos Fragkakis


People also ask

What are true about ordering collections in Hibernate?

- The sorting occurs in the memory of JVM which running Hibernate, after the data being read from database using java comparator. - The efficiency depends on the size of the collection. - Ordered collection is sorted by specifying the order-by clause for sorting this collection when retrieval.

Which is sorted in normal order in Hibernate?

In hibernate a sorted collection is sorted in memory being Java the responsible of sorting data using compareTo method. Obviously this method is not the best performance-way to sort a collection of elements.

Is ORDER BY supported in HQL?

In HQL we perform order by and group by for the given property of entity or associated entities.


2 Answers

Hibernate supports mapping a collection as a SortedSet. In your mappings you basically just need to specify an order-by clause. Take a look at this chapter in the reference manual.

like image 51
matt b Avatar answered Sep 28 '22 12:09

matt b


Like said Markos Fragkakis

unfortunately order-by in the mapping (or @OrderBy) takes precedence, which makes the ordering set by the Criteria useless.

But you must set @Order if you want to have the Set ordered.

You can still use HQL instead ( tested on hibernate 3.3.2.GA ) who order firstly by the order in the hql query :

    @Entity
    @Table(name = "Person")
    public class Person  {

        @Id
        @Column(name = "ID_PERSON", unique = true, nullable = false, precision = 8, scale = 0)
        private Long id;

        @OneToMany(fetch = FetchType.LAZY, mappedBy = "person")
        @OrderBy
        private Set<Book> books = new HashSet<Book>(0);

        public Person() {
        }

        public Long getId() {
            return this.id;
        }

        public void setId(Long id) {
            this.id = id;
        }


      public Set<Book> getBooks() {
            return this.books;
        }

        public void setBooks(Set<Book> books) {
            this.books = books;
        }

    }

      /** 
       *  hql Version 
       *    
       *  Result in : 
       *  order by
       *      book1_.TITLE asc,
       *      book1_.ID_BOOK asc  
       **/

        @Override
        public Person getFullPerson(Long idPerson) {

            StringBuilder hqlQuery =  new StringBuilder();
            hqlQuery.append("from Person as p ");
            hqlQuery.append("left join fetch p.books as book ");
            hqlQuery.append("where p.id = :idPerson ");
            hqlQuery.append("order by book.title ");
            Query query = createQuery(hqlQuery.toString());
            query.setLong("idPerson", id);
            return uniqueResult(query);

        }




      /** 
       *  criteria  Version // not usable 
       *    
       *  Result in : 
       *  order by
       *      book1_.ID_BOOK asc,
       *      book1_.TITLE asc  
       **/

      @Override
    public Person getFullPersonCriteria(Long idPerson) {

        Criteria criteria = ...
        criteria.add(Restrictions.eq("id", idPerson));
        criteria.createAlias("books", "book", CriteriaSpecification.LEFT_JOIN);
        criteria.addOrder(Order.asc("book.title"));
            return criteria.uniqueResult();
      }
like image 36
Grégory Avatar answered Sep 28 '22 10:09

Grégory