问题 Hibernate:订购一套


我有一个有一套书的人。在特定情况下,拥有有序或有序集合是没有意义的。

现在说我有一个搜索页面,其中有一个表格显示了Person和Book的连接。我希望能够通过Person和Book中的字段对结果进行排序,然后从Hibernate获取List,并迭代它。

因为集合是一个集合,所以书籍的排序已经消失(Hibernate的PersistentSet包装了一个HashSet of Books,它没有被订购)。

因此,通过这种方法,我无法通过Book字段排序结果。

如果我将集合从Set更改为List,我的模型在语义上是不正确的。保持模型中的顺序没有意义。

有没有办法保持书籍的顺序?也许PersistentSet有一种方法可以包装一个LinkedHashSet(有序),其中的顺序由我的搜索条件定义?

干杯!


2036
2018-04-01 13:17


起源



答案:


Hibernate支持将集合映射为 SortedSet。在你的映射中,你基本上只需要指定一个 order-by 条款。看一眼 本章参考手册


6
2018-04-01 13:23



感谢您的回复(+1)。是的,我已经看到了。但在这个例子中,他们已经确定了排序是在某个领域。我希望通过Criteria API设置该字段,具体取决于用户在UI中单击的内容。 - Markos Fragkakis
您也可以在Criteria查询中指定结果的排序,与映射中指定的内容分开。 docs.jboss.org/hibernate/stable/core/reference/en/html/... - matt b
是的,你可以,但不幸的是,映射(或@OrderBy)中的order-by优先,这使得Criteria设置的排序无用。或者至少,它是在对映射的顺序排序之后发生的。 - Markos Fragkakis
同时更改了指示的URL,这里是更新的URL: docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/... - isti_spl


答案:


Hibernate支持将集合映射为 SortedSet。在你的映射中,你基本上只需要指定一个 order-by 条款。看一眼 本章参考手册


6
2018-04-01 13:23



感谢您的回复(+1)。是的,我已经看到了。但在这个例子中,他们已经确定了排序是在某个领域。我希望通过Criteria API设置该字段,具体取决于用户在UI中单击的内容。 - Markos Fragkakis
您也可以在Criteria查询中指定结果的排序,与映射中指定的内容分开。 docs.jboss.org/hibernate/stable/core/reference/en/html/... - matt b
是的,你可以,但不幸的是,映射(或@OrderBy)中的order-by优先,这使得Criteria设置的排序无用。或者至少,它是在对映射的顺序排序之后发生的。 - Markos Fragkakis
同时更改了指示的URL,这里是更新的URL: docs.jboss.org/hibernate/orm/4.1/manual/en-US/html_single/... - isti_spl


就像Markos Fragkakis说的那样

遗憾的是,映射(或@OrderBy)中的order-by优先,这使得Criteria设置的排序无用。

但是如果你想让Set有序,你必须设置@Order。

您仍然可以使用HQL(在hibernate 3.3.2.GA上测试),它首先按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();
      }

4
2017-09-25 10:40





这是一种内存中的排序,它将处理连接表中的重复项。

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

3
2017-08-01 17:13





不确定我是否正确的问题,但如果您只想要列表的ordererd版本,您可以使用java.util.Collections类和Comparator对其进行排序。也许你想在你的pojo上制作一个瞬态方法,如下所示:

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

只需编写一个实现Comparator的Class。


0
2018-01-06 13:36



-1:这适用于列表,但不适用于集合,每次调用getter时都会对列表进行排序。 - Kojotak
如果您使用的集合在每次添加/删除时都不保留其排序,则必须在每次调用时对集合进行排序。 - mojoo-de