| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 | @EntitypublicclassStarship { @Id@GeneratedValue(strategy=GenerationType.SEQUENCE)  privateLong id; publicLong getId() {returnid;} protectedvoidsetId(Long id) {this.id = id;} @OneToMany(mappedBy="starship", cascade={CascadeType.ALL})  privateList<Officer> officers = newArrayList<Officer>(); publicList<Officer> getOfficers() {returnCollections.unmodifiableList(officers);} protectedvoidsetOfficers(List<Officer> officers) {this.officers = officers;} publicvoidaddOfficer(Officer officer) {  officer.setStarship(this);  this.officers.add(officer); }        //more code}@EntitypublicclassOfficer { @Id@GeneratedValue(strategy=GenerationType.SEQUENCE)  privateLong id; publicLong getId() {returnid;} protectedvoidsetId(Long id) {this.id = id;} @ManyToOneprivateStarship starship;  publicStarship getStarship() {returnstarship;} protectedvoidsetStarship(Starship starship) {this.starship = starship;}        //more code} | 
  Теперь у нас есть следующее требование: 
  Мы назначим всех офицеров на звездолет в алфавитном порядке. 
  Для решения этого требования мы можем: 
- реализация HQL- запроса с предложением order by .
- используя сортировку
- используя порядок заказа .
  Первое решение хорошо с точки зрения производительности, но подразумевает большую работу в качестве разработчиков, потому что мы должны написать запрос, чтобы найти всех офицеров данного звездолета, упорядоченных по имени, а затем создать метод поиска в слое DAO (в случае, если вы используете шаблон DAO ) , 
  Давайте рассмотрим второе решение, мы могли бы использовать класс SortedSet в качестве ассоциации и сделать Officer реализуемым Comparable , чтобы у Officer было   естественный порядок.  Это решение подразумевает меньше работы, чем первое, но требует использования аннотации @Sort hibernate для определения ассоциации. Итак, давайте изменим предыдущую модель, чтобы она соответствовала нашему новому требованию. Обратите внимание, что в спецификации JPA нет эквивалентной аннотации. 
  Сначала мы собираемся реализовать 
| 01 02 03 04 05 06 07 08 09 10 11 | @EntitypublicclassOfficer implementsComparable<Officer>{        //getters, setters, equals, ... code publicintcompareTo(Officer officer) {  returnthis.name.compareTo(officer.getName()); }} | 
Сопоставимый интерфейс в классе Officer .
Мы заказываем офицера по имени, просто сравнивая имя поля. Следующим шагом является аннотирование ассоциации с @Sort .
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | @EntitypublicclassStarship {        //more code @OneToMany(mappedBy="starship", cascade={CascadeType.ALL}) @Sort(type=SortType.NATURAL) privateSortedSet>Officer< officers = newTreeSet>Officer<(); publicSortedSet>Officer< getOfficers() {returnCollections.unmodifiableSortedSet(officers);} protectedvoidsetOfficers(SortedSet>Officer< officers) {this.officers = officers;} publicvoidaddOfficer(Officer officer) {  officer.setStarship(this);  this.officers.add(officer); }} | 
Обратите внимание, что теперь ассоциация офицеров реализована с использованием SortedSet вместо List . Кроме того, мы добавляем аннотацию @Sort к отношениям, заявляя, что офицеры должны быть в естественном порядке. Перед тем, как закончить этот пост, мы будем настаивать больше в теме @Sort , но пока этого достаточно.
И, наконец, метод, позволяющий упорядочить всех офицеров данного звездолета по имени и распечатать их в лог-файле.
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 | EntityManager entityManager = this.entityManagerFactory.createEntityManager();EntityTransaction transaction = entityManager.getTransaction();transaction.begin();log.info("Before Find Starship By Id");Starship newStarship = entityManager.find(Starship.class, starshipId);SortedSet<Officer> officers = newStarship.getOfficers(); for(Officer officer : officers) { log.info("Officer name {} with rank {}", officer.getName(), officer.getRank());}  log.info("After Find Starship By Id and Before Commit");transaction.commit();entityManager.close(); | 
Все офицеры отсортированы по именам, но давайте рассмотрим, какие запросы отправляются в СУБД .
| 1 2 3 4 5 | Hibernate: selectstarship0_.idas id1_0_, starship0_.affiliationEnum as affiliat2_1_0_, starship0_.launched as launched1_0_, starship0_.height as height1_0_, starship0_.length as length1_0_, starship0_.power as power1_0_, starship0_.width as width1_0_, starship0_.registry as registry1_0_, starship0_.starshipClassEnum as starship9_1_0_ from Starship starship0_ where starship0_.id=?Hibernate: selectofficers0_.starship_id as starship7_1_1_, officers0_.idas id1_, officers0_.idas id0_0_, officers0_.affiliationEnum as affiliat2_0_0_, officers0_.homePlanet as homePlanet0_0_, officers0_.name as name0_0_, officers0_.rank as rank0_0_, officers0_.speciesEnum as speciesE6_0_0_, officers0_.starship_id as starship7_0_0_ from Officer officers0_ where officers0_.starship_id=? | 
Первый запрос является результатом вызова метода find на экземпляре EntityManager для поиска звездолета.
Поскольку отношения один ко многим по умолчанию являются ленивыми, когда мы вызываем метод getOfficers и мы впервые обращаемся к SortedSet , выполняется второй запрос для получения всех сотрудников. Обратите внимание, что в запросе нет порядка по пунктам, но, внимательно изучив выходные данные, сотрудники извлекаются в алфавитном порядке.
| 1 2 3 4 5 6 7 | <Officer name Beverly Crusher with rank COMMANDER><Officer name Data with rank LIEUTENANT_COMMANDER><Officer name Deanna Troi with rank COMMANDER><Officer name Geordi La Forge with rank LIEUTENANT><Officer name Jean-Luc Picard with rank CAPTAIN><Officer name William Riker with rank COMMANDER><Officer name Worf with rank LIEUTENANT> | 
  Так кто же сортирует офицерские сущности?  Объяснение на аннотации @Sort .  В hibernate отсортированная коллекция сортируется в памяти, так как Java отвечает за сортировку данных с помощью метода CompareTo . 
  Очевидно, что этот метод не лучший способ производительности для сортировки коллекции элементов.  Вероятно, нам понадобится гибридное решение между использованием предложения SQL и использованием аннотации вместо написания запроса. 
И это приводит нас к объяснению третьей возможности, используя подход к упорядочению. Аннотация @OrderBy , доступная как аннотация hibernate и аннотация JPA , позволяет нам указать, как упорядочить коллекцию, добавив предложение « order by » в сгенерированный SQL .
  Имейте в виду, что использование javax.persistence.OrderBy позволяет нам определять порядок коллекции с помощью свойств объекта, в то время как org.hibernate.annotations.OrderBy упорядочивает коллекцию, добавляя непосредственно фрагмент SQL (не HQL ) для упорядочения по предложению. 
  Теперь к классу Officer не нужно прикасаться, нам не нужно реализовывать метод CompareTo или java.util.Comparator .  Нам нужно только аннотировать поле офицеров аннотацией @OrderBy .  Поскольку в этом случае мы упорядочиваем по простому атрибуту, аннотация JPA используется для обеспечения полной совместимости с другими механизмами ORM, « готовыми к JPA ».  По умолчанию предполагается восходящий порядок. 
| 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | @EntitypublicclassStarship {        //code @OneToMany(mappedBy="starship", cascade={CascadeType.ALL}) @OrderBy("name") privateList<Officer> officers = newArrayList<Officer>(); publicList<Officer> getOfficers() {returnCollections.unmodifiableList(officers);} protectedvoidsetOfficers(List<Officer> officers) {this.officers = officers;} publicvoidaddOfficer(Officer officer) {  officer.setStarship(this);  this.officers.add(officer); }}  | 
И если мы перезапустим метод get all employee, будут отправлены следующие запросы:
| 1 2 3 4 5 | Hibernate: select starship0_.id as id1_0_, starship0_.affiliationEnum as affiliat2_1_0_, starship0_.launched as launched1_0_, starship0_.height as height1_0_, starship0_.length as length1_0_, starship0_.power as power1_0_, starship0_.width as width1_0_, starship0_.registry as registry1_0_, starship0_.starshipClassEnum as starship9_1_0_ from Starship starship0_ where starship0_.id=?Hibernate: select officers0_.starship_id as starship7_1_1_, officers0_.id as id1_, officers0_.id as id0_0_, officers0_.affiliationEnum as affiliat2_0_0_, officers0_.homePlanet as homePlanet0_0_, officers0_.name as name0_0_, officers0_.rank as rank0_0_, officers0_.speciesEnum as speciesE6_0_0_, officers0_.starship_id as starship7_0_0_ from Officer officers0_ where officers0_.starship_id=? order by officers0_.name asc | 
Оба запроса все еще выполняются, но имейте в виду, что теперь запрос select также содержит предложение order by .
  С этим решением вы экономите время процесса, позволяя быстрой сортировке данных СУБД , а не упорядочиваете данные в Java после их получения. 
  Кроме того, аннотация OrderBy не заставляет вас использовать коллекцию SortedSet или SortedMap .  Вы можете использовать любую коллекцию, такую как HashMap , HashSet или даже Bag , потому что hibernate будет внутренне использовать LinkedHashMap , LinkedHashSet или ArrayList соответственно. 
В этом примере мы увидели важность правильного выбора стратегии заказа. По возможности, вы должны стараться использовать возможности СУБД , поэтому первым вариантом будет использование аннотации OrderBy ( hibernate или JPA ) вместо сортировки . Но иногда оговорки OrderBy будет недостаточно. В этом случае я рекомендую вам использовать аннотацию Sort с пользовательским типом (используя класс java.util.Comparator ) вместо того, чтобы использовать естественный порядок, чтобы не касаться классов моделей.
| 1 | @Sort(type=SortType.COMPARATOR, comparator=TimeComparator.class) | 
Я хотел бы, чтобы этот пост помог вам понять разницу между «сортировать» и «порядок» в спящем режиме .
Продолжай учиться.
Ссылка: Hibernate Совет: сортировка и заказ от нашего партнера JCG Алекса Сото в блоге One Jar To Rule All .