JPA/спящий сортированный сборник @OrderBy vs @Sort
Я хотел бы иметь набор дочерних объектов (здесь пример кошки-котенка), которые упорядочены. И сохраните свой порядок при добавлении новых элементов.
@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)
, порядок по имени будет нарушен.
Возможно ли, чтобы спящий режим выполнял работу по упорядочению коллекции? Используя аннотацию @Sort hibernate?
@Sort имеет тот недостаток, что он заставляет вас реализовать интерфейс Comparable...
Каким будет правильный "чистый JPA" способ сделать это? Сохранение всего в БД и его перезагрузка?
Имеет смысл объединить @OrderBy и @Sort?
Обновление
Решение до сих пор заключается в объединении @OrderBy и @Sort. @OrderBy приводит к предложению ORDER BY
в сгенерированном SQL, который лучше подходит для производительности (я предполагаю, что 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; }
}
Ответы
Ответ 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.
Update:
Я не уверен, насколько придирчивый Hibernate с определениями getter/setter, но с EclipseLink мне удалось полностью удалить сеттер и обернуть List
, возвращенный моим получателем в вызове Collections.unmodifiableList(...)
. Затем я определил специальные методы для изменения коллекции. Вы можете сделать то же самое и заставить вызывающих использовать метод добавления, который вставляет элементы в отсортированном порядке. Если Hibernate жалуется, что у вас нет геттера/сеттера, возможно, вы можете изменить модификатор доступа? Я думаю, это сводится к тому, насколько вы готовы пойти, чтобы избежать нестандартных зависимостей.
Ответ 2
В последней версии Hibernate используются новые аннотации для этого:
@SortNatural
@OrderBy("name ASC")
private SortedSet<Kitten> kittens = new TreeSet<>();
Есть две части:
- Аннотация
@OrderBy
указывает, что предложение order by
должно быть добавлено в запрос базы данных при извлечении связанных записей.
- Аннотация
@SortNatural
предполагает, что Kitten
реализует интерфейс Comparable
и использует эту информацию при построении экземпляра TreeSet
. Обратите внимание, что вы можете заменить его на аннотацию @SortComparator
, которая позволяет указать класс Comparator
, который будет передан конструктору TreeSet
.
См. документацию: https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#collections-sorted-set
Ответ 3
@Entity
public class Cat {
@OneToMany(mappedBy = "cat", cascade = CascadeType.ALL)
private Set<Kitten> kittens = new TreeSet<>();
}
Не нужно писать
@OrderBy("name ASC")
Make Sure Kitten Class реализует совместимый интерфейс.