2010-04-01 13 views
11

Ho una classe Persona che ha un set di libri. Nel caso specifico non è significativo avere una collezione ordinata o ordinata.Hibernate: ordina un set

Dire ora che ho una pagina di ricerca con una tabella che mostra l'unione di Persona e Libro. Voglio essere in grado di ordinare i risultati in base ai campi di Persona e Libro, quindi ottenere un elenco da Hibernate e scorrere su di esso.

Poiché la raccolta è un set, l'ordinamento dei libri è scomparso (PersistentSet of Hibernate racchiude un hash di libri, che non è ordinato).

Quindi, con questo approccio non posso avere risultati ordinati anche per i campi del libro.

Se cambio la raccolta da Imposta a Elenco, il mio modello è semanticamente errato. Non vi è alcun significato per mantenere l'ordine nel modello.

Esiste un approccio per mantenere l'ordine dei libri? Forse c'è un modo per PersistentSet per racchiudere un LinkedHashSet (che è ordinato), dove l'ordine è definito dai miei criteri di ricerca?

Cheers!

risposta

6

Hibernate supporta il mapping di una raccolta come SortedSet. Nei tuoi mapping devi semplicemente specificare una clausola order-by. Dai uno sguardo allo this chapter in the reference manual.

+1

Grazie per la risposta (+1). Sì, l'ho visto. Ma nell'esempio hanno stabilito che l'ordine si trova su un determinato campo. Voglio che i campi vengano impostati tramite l'API Criteri, a seconda di ciò che l'utente ha fatto clic sull'interfaccia utente. –

+1

È anche possibile specificare un ordine per i risultati in una query Criteria, separata da qualsiasi cosa specificata nella mappatura. http://docs.jboss.org/hibernate/stable/core/reference/en/html/querycriteria.html#querycriteria-ordering –

+1

Sì, è possibile, ma purtroppo il order-by nella mappatura (o @OrderBy) ha la precedenza , che rende inutile l'ordine impostato dai Criteri. O almeno, viene dopo l'ordinamento dell'ordine della mappa. –

0

Non so se ho ottenuto la domanda giusta, ma se vuoi solo una versione ordinata della tua lista puoi semplicemente ordinarla con la classe java.util.Collections e un comparatore. Forse vuoi fare un Metodo transitorio sul tuo pojo in questo modo:

@Transient 
public List<Book> getBooksASC() 
{ 
    Collections.sort(this.books, new BookSorter.TitelASCSorter()); 
    return this.books; 
} 

Basta scrivere una Classe che implementa Comparatore.

+0

-1: funziona per gli elenchi, ma non per gli insiemi e l'elenco viene ordinato ogni volta che viene chiamato il getter. – Kojotak

+0

devi ordinare la raccolta su ogni chiamata, se usi una raccolta che non mantiene il suo ordine su ogni aggiunta/rimozione. –

4

Come detto Markos Fragkakis

purtroppo ordine-by nella mappatura (o @OrderBy) prevale, il che rende l'ordinamento fissato dai criteri inutili.

Ma è necessario impostare @ Ordine se si desidera che il Set sia ordinato.

È comunque possibile utilizzare HQL invece (testato su hibernate 3.3.2.GA) che ordinano in primo luogo l'ordine nella query HQL:

@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(); 
     } 
3

Questo è un in-memory tipo che si prenderà cura di duplicati nella tabella di join.

@OneToMany 
    @JoinTable(name = "person_book", joinColumns = @JoinColumn(name = "person_id"), 
      inverseJoinColumns = @JoinColumn(name = "book_id")) 
    @Sort(type = SortType.COMPARATOR, comparator = MyBookComparator.class) 
    private SortedSet<BookEntity> books; 
Problemi correlati