2010-04-01 17 views
11

Mam klasę Osoba, która ma zestaw książek. W konkretnym przypadku nie ma sensu posiadanie uporządkowanej lub posortowanej kolekcji.Hibernate: zamawianie zestawu

Teraz powiedz, że mam stronę wyszukiwania z tabelą przedstawiającą połączenie osoby i książki. Chcę być w stanie sortować wyniki według pól zarówno od osoby i książki, a następnie uzyskać listę z hibernacji i iteracji nad nim.

Ponieważ kolekcja jest zbiorem, kolejność książek zniknęła (zestaw persystyczny (PersistentSet of Hibernate) opakowuje HashSet of Books, który nie jest uporządkowany).

Dzięki temu podejściu nie mogę mieć wyników również uporządkowanych według pól książki.

Jeśli zmienię kolekcję z Ustaw na listę, mój model jest semantycznie niepoprawny. Nie ma sensu utrzymywać porządek w modelu.

Czy istnieje sposób na zachowanie porządku książek? Być może istnieje sposób, aby PersistentSet opakował LinkedHashSet (który jest uporządkowany), gdzie kolejność jest zdefiniowana przez moje kryteria wyszukiwania?

Pozdrawiam!

Odpowiedz

6

Hibernate obsługuje mapowanie kolekcji jako SortedSet. W swoich mapowaniach po prostu musisz podać klauzulę order-by. Spójrz na this chapter in the reference manual.

+1

Dzięki za odpowiedź (+1). Tak, widziałem to. Ale w tym przykładzie ustalili, że zamówienie jest na pewnym polu. Chcę, aby to pole (pola) były ustawione za pośrednictwem API Criteria, w zależności od tego, co użytkownik kliknął w interfejsie użytkownika. –

+1

Możesz również określić kolejność wyników w zapytaniu Kryteria, niezależnie od tego, co określisz w odwzorowaniu. http://docs.jboss.org/hibernate/stable/core/reference/en/html/querycriteria.html#querycriteria-ordering –

+1

Tak, możesz, ale niestety kolejność w mapowaniu (lub @OrderBy) ma pierwszeństwo , co sprawia, że ​​porządek ustawiony według kryteriów jest bezużyteczny. A przynajmniej przychodzi po sortowaniu kolejności według mapowania. –

0

Nie wiem, czy mam pytanie poprawnie, ale jeśli chcesz tylko zamówić wersję listy, możesz posortować ją za pomocą klasy java.util.Collections i komparatora. Może chcesz stworzyć przejściową metodę na twoim pojo w ten sposób:

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

Wystarczy napisać klasę, która implementuje Komparator.

+0

-1: Działa to dla list, ale nie dla zestawów, a lista jest sortowana za każdym razem, gdy wywoływany jest wywoływacz. – Kojotak

+0

musisz sortować kolekcję przy każdym połączeniu, jeśli korzystasz z kolekcji, która nie zachowuje zamówienia przy każdym dodaniu/usunięciu. –

4

Like powiedział Markos Fragkakis

niestety order-by w mapowaniu (lub @OrderBy) ma pierwszeństwo, co sprawia, kolejność ustaloną przez Kryteriów bezużyteczne.

Musisz jednak ustawić @Zamknij, jeśli chcesz zamówić Zestaw.

Można nadal używać zamiast HQL (testowane na hibernacji 3.3.2.GA), który najpierw zamówić przez porządek w kwerendzie 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

Jest to w pamięci sortowania że zajmie duplikaty w tabeli łączenia.

@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;