OrderBy или OrderColumn

Между JPA аннотациями @OrderBy и @OrderColumn есть существенное различие.

@OrderBy — аналог обычной SQL команды ORDER BY. Здесь всё понятно. Например, у вас отношение один ко многим. Для примера возьмём сущность «Новость» и к ней привязано несколько «Комментариев». На уровне объектной модели, это значит, что у вас есть объект класса News, у которого есть метод который возвращает список комментариев:

+-----------------------------+
|News                         |
|-----------------------------|
|-----------------------------|
|+getComments(): List<Comment>|
+-----------------------------+

+-----------------+
|Comment          |
|-----------------|
|-----------------|
|+getNews(): News |
+-----------------+

В таком случае, мы должны указать в классе News:

// тут аннотации
public class News {

    @OneToMany(targetEntity = Comment.class, mappedBy="news")
    @OrderBy(value="pubdate desc")
    private List comments;

    // дальше какой-то код еще ...    
}

Причем сортировка должна быть сделана на уровне БД, через ORDER BY выражение. В данном примере мы сортируем комментарии, по дате их публикации (поле pubdate).

@OrderColumn — задает другой способ оказания порядка (материализованный). В этом случае порядковый номер записи указывается явно в таблице. В Hibernate была аналогичная аннотация @IndexColumn , ее использовали до выхода JPA 2.0. Сейчас по возможности лучше вместо @IndexColumn использовать @OrderColumn. В Hibernate поддерживаются обе.

Разберём пример. Допустим, у вас опять используется отношение один ко многим, но в этом случае возьмем сущность «Дом» в котором живут несколько «Постояльцев». В этом доме в 1-ом номере остановились Ивановы, во 2-ом Петровы, с 3 и 4 — пустуют, в 5 — Кузнецовы.

0 - null
1 - Ивановы
2 - Петровы
3 - null
4 - null
5 - Кузнецовы

Для того, чтобы сохранить информацию кто в каком номере живет, мы явно указываем в табличке с жильцами номер комнаты (поле room).

+-------------------------------+
|House                          |
|-------------------------------|
|-------------------------------|
|+getResidents(): List<Resident>|
+-------------------------------+
+----------------------+
|Resident              |
|----------------------|
| room:Integer         |
+----------------------+

В таком случае, мы пишем в классе House:

// аннотации
public class House {
    // ...
    @OneToMany(targetEntity = Resident.class,  mappedBy="house")
    @OrderColumn(name="room")
    private List residents;

}

Внимание! Теперь самое важное. Если в данном случае использовать OrderColumn, то у нас будет список в котором будут дыры! С другой стороны, мы можем сразу по порядковому номеру в списке определить номер комнаты.

// жители:
List list = house.getResidents();
// 2 - Петровы
Resident petrovy = list.get(2) ; 

Отличие от OrderBy фундаментальное.

Если вы неправильно спроектируете зависимости и укажите в первом примере (новости — комментарии) вместо OrderBy аннотацию OrderColumn по «дате публикации», то у вас может возникнуть как явная ошибка, так и неявная ошибка, например по причине конвертации поля даты в число. Зависит от БД и ORM.
Например, в MySQL + Hibernate это может сработать следующим образом. Дата публикации «01.01.2011» — преобразуется в число «2011», в итоге получаем список из null-ов, а в конце после 2011-ной записи — комментарии.

Об авторе
Более 20 лет в разработке ПО, специализируюсь на Java. Опыт в создании масштабируемых и высокопроизводительных систем, разработке мобильных приложений. Подробнее об авторе и правилах использования контента – на странице @author.

  Подписывайтесь на Telegram-канал@prgrmdr