JPA / hibernate排序集合@OrderBy vs @Sort

时间:2022-03-14 06:48:13

I would like to have a collection of child objects (here cat-kitten example) that are ordered. And keep their order on adding of new elements.

我想要一个订购的子对象(这里是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; } 
}

When I do cat.getKittens.add(newKitten) the order by name will be broken.

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

Is it possible to let hibernate do the work of keeping the collection always ordered? By using the @Sort hibernate annotation?
@Sort has the disadvantage that it forces you to implement Comparable interface ... What would be the right 'pure JPA' way to do that? Saving everything to DB and reloading it? Makes it sense to combine @OrderBy and @Sort?

是否有可能让hibernate完成保持集合总是有序的工作?通过使用@Sort hibernate注释? @Sort的缺点是它迫使你实现Comparable接口......什么是正确的'纯JPA'方法呢?将所有内容保存到数据库并重新加载?合并@ OrderBy和@Sort是否合理?

Update Solution up to now is to combine @OrderBy and @Sort. @OrderBy leads to a ORDER BY clause in the generated SQL which is better for performance (I assume that java is "sorting" again on inserting into the sorted container, but that should be much faster because the elements are already sorted) @Sort together with an implemented Comparable interface leads to a always sorted container. Note that I use now SortedSet instead of List. Here the updated Code:

到目前为止,更新解决方案是将@ OrderBy和@Sort结合起来。 @OrderBy导致生成的SQL中的ORDER BY子句对性能更好(我假设java在插入到已排序的容器时再次“排序”,但这应该快得多,因为元素已经排序)@Sort together使用已实现的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; } 
}

3 个解决方案

#1


20  

If you want to avoid non-standard annotations, you could make kittens use some sorted Collection implementation. This would ensure that kittens is always in sorted order. Something like this:

如果您想避免使用非标准注释,可以让小猫使用一些已排序的Collection实现。这将确保小猫始终按排序顺序排列。像这样的东西:

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

Note that this approach also requires Kitten to implement Comparable (alternatively, you could pass a Comparator to your TreeSet constructor). Also, I'm using a Set because I'm not aware of any standard sorted List implementation and I'm assuming the Cat does not have any clones in its litter =p.

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

Update: I'm not sure how picky Hibernate is with its getter/setter definitions, but with EclipseLink I've been able to remove a setter entirely and wrap the List returned by my getter in a Collections.unmodifiableList(...) call. I then defined special methods for modifying the collection. You could do the same thing and force callers to use an add method that inserts elements in sorted order. If Hibernate complains about not having the getter/setter, maybe you could change the access modifier? I guess it comes down to how far you're willing to go to avoid non standard dependencies.

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

#2


13  

The latest version of Hibernate uses new annotations to accomplish this:

最新版本的Hibernate使用新注释来完成此任务:

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

There are two parts to this:

这有两个部分:

  1. The @OrderBy annotation specifies that an order by clause should be added to the database query when fetching the related records.
  2. @OrderBy批注指定在获取相关记录时应将order by子句添加到数据库查询中。
  3. The @SortNatural annotation assumes that Kitten implements the Comparable interface and uses that information when constructing the TreeSet instance. Note that you can replace this with the @SortComparator annotation, which allows you to specify a Comparator class that will be passed to the TreeSet constructor.
  4. @SortNatural注释假定Kitten实现Comparable接口并在构造TreeSet实例时使用该信息。请注意,您可以将其替换为@SortComparator注释,该注释允许您指定将传递给TreeSet构造函数的Comparator类。

See documentation: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#collections-sorted-set

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

#3


-2  

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

No need to write

不需要写

@OrderBy("name ASC")

Make Sure Kitten Class implements Comparable interface properly.

使Sure Kitten Class正确实现Comparable接口。

#1


20  

If you want to avoid non-standard annotations, you could make kittens use some sorted Collection implementation. This would ensure that kittens is always in sorted order. Something like this:

如果您想避免使用非标准注释,可以让小猫使用一些已排序的Collection实现。这将确保小猫始终按排序顺序排列。像这样的东西:

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

Note that this approach also requires Kitten to implement Comparable (alternatively, you could pass a Comparator to your TreeSet constructor). Also, I'm using a Set because I'm not aware of any standard sorted List implementation and I'm assuming the Cat does not have any clones in its litter =p.

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

Update: I'm not sure how picky Hibernate is with its getter/setter definitions, but with EclipseLink I've been able to remove a setter entirely and wrap the List returned by my getter in a Collections.unmodifiableList(...) call. I then defined special methods for modifying the collection. You could do the same thing and force callers to use an add method that inserts elements in sorted order. If Hibernate complains about not having the getter/setter, maybe you could change the access modifier? I guess it comes down to how far you're willing to go to avoid non standard dependencies.

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

#2


13  

The latest version of Hibernate uses new annotations to accomplish this:

最新版本的Hibernate使用新注释来完成此任务:

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

There are two parts to this:

这有两个部分:

  1. The @OrderBy annotation specifies that an order by clause should be added to the database query when fetching the related records.
  2. @OrderBy批注指定在获取相关记录时应将order by子句添加到数据库查询中。
  3. The @SortNatural annotation assumes that Kitten implements the Comparable interface and uses that information when constructing the TreeSet instance. Note that you can replace this with the @SortComparator annotation, which allows you to specify a Comparator class that will be passed to the TreeSet constructor.
  4. @SortNatural注释假定Kitten实现Comparable接口并在构造TreeSet实例时使用该信息。请注意,您可以将其替换为@SortComparator注释,该注释允许您指定将传递给TreeSet构造函数的Comparator类。

See documentation: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#collections-sorted-set

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

#3


-2  

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

No need to write

不需要写

@OrderBy("name ASC")

Make Sure Kitten Class implements Comparable interface properly.

使Sure Kitten Class正确实现Comparable接口。