【问题标题】:JPA/hibernate sorted collection @OrderBy vs @SortJPA/hibernate 排序集合 @OrderBy 与 @Sort
【发布时间】:2013-11-21 05:06:49
【问题描述】:

我想要一组有序的子对象(这里是 cat-kitten 示例)。并保持他们添加新元素的顺序。

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

当我执行cat.getKittens.add(newKitten) 时,按名称排序将被破坏。

是否可以让 hibernate 完成保持集合始终有序的工作?通过使用@Sort hibernate 注释?
@Sort 的缺点是它迫使你实现 Comparable 接口...... 什么是正确的“纯JPA”方式来做到这一点?将所有内容保存到数据库并重新加载? 将@OrderBy 和@Sort 结合起来有意义吗?

更新 到目前为止的解决方案是结合@OrderBy 和@Sort。 @OrderBy 导致生成的 SQL 中的 ORDER BY 子句对性能更好(我假设 java 在插入排序容器时再次“排序”,但这应该更快,因为元素已经排序) @Sort 与实现的Comparable 接口一起导致始终排序的容器。请注意,我现在使用 SortedSet 而不是 List。这里是更新的代码:

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

【问题讨论】:

标签: hibernate jpa collections sql-order-by sorted


【解决方案1】:

如果你想避免非标准的注释,你可以让kittens 使用一些排序的Collection 实现。这将确保kittens 始终处于排序状态。像这样的:

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

请注意,这种方法还需要Kitten 来实现Comparable(或者,您可以将Comparator 传递给您的TreeSet 构造函数)。另外,我使用的是Set,因为我不知道任何标准排序的List 实现,并且我假设Cat 在其垃圾中没有任何克隆=p。

更新: 我不确定 Hibernate 对它的 getter/setter 定义有多挑剔,但是使用 EclipseLink 我已经能够完全删除一个 setter 并将我的 getter 返回的 List 包装在 Collections.unmodifiableList(...) 调用中。然后我定义了修改集合的特殊方法。您可以做同样的事情并强制调用者使用按排序顺序插入元素的 add 方法。如果 Hibernate 抱怨没有 getter/setter,也许您可​​以更改访问修饰符?我想这取决于你愿意走多远来避免非标准依赖。

【讨论】:

  • 使用SortedSet接口会不会更好?因为用= new TreeSet&lt;&gt;()的初始化在hibernate生成的时候会被替换掉。 Set 导致 PersistentSet 在内部使用 LinkedHashSet(您丢失了 TreeSet 并只保留插入顺序,对吗?)。 SortedSet 将被内部使用的 PersistentSortedSet 替换,最后是 TreeSet... 注意:使用 SortedSet 会强制您指定 @Sort 注释:-/
  • 啊...我不知道 Hibernate 会这样做。我在 EclipseLink 中使用过类似的方法,但恐怕我对 Hibernate 不太熟悉
  • 用另一个想法更新了我的答案。不是最干净的解决方案,但我想我会把它扔在那里。
  • 谢谢!在“纯 JPA”和“更少代码”之间的权衡中,我在这种情况下选择“更少代码”。其他项目可能会有所不同...
  • 如果有人在尝试使用最新版本的 Hibernate 完成此操作时迷路了,请参阅下面的答案:stackoverflow.com/a/42170280/1988326
【解决方案2】:

最新版本的 Hibernate 使用了新的注解来实现这一点:

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

这有两个部分:

  1. @OrderBy 注释指定在获取相关记录时应将order by 子句添加到数据库查询中。
  2. @SortNatural 注释假定Kitten 实现Comparable 接口并在构造TreeSet 实例时使用该信息。请注意,您可以将其替换为 @SortComparator 注释,它允许您指定将传递给 TreeSet 构造函数的 Comparator 类。

查看文档:https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#collections-sorted-set

【讨论】:

  • 这对我有用``` @Setter @Getter @ManyToMany(fetch = FetchType.EAGER, cascade = CascadeType.DETACH, mappedBy = "trending") @SortNatural @OrderBy("creationDate desc ")私人列表 推文; ```
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-26
  • 2012-11-03
  • 1970-01-01
  • 2014-12-02
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多