Возможно ли сделать сортировку в JPQL по свойству enum?

Сущность:

@Entity
@Table(name = "shapes")
public class Shape {

    @Id
    Integer id;

    @Column(name = "type")
    @Enumerated(EnumType.STRING)
    ShapeType type;
}

Enum:

public enum ShapeType {

    RECTANGLE("Прямоугольник"),
    SQUARE("Квадрат"),
    CIRCLE("Круг");

    private final String name;

    ShapeType(name) {
        this.name = name;
    }
}

Я хочу сделать сортировку по свойству name поля type при получении списка фигур. В моём понимании это было бы как-то так:

@Query("SELECT s FROM Shape s ORDER BY s.type.name ASC")
List<Shape> getAll();

Но такой запрос генерирует ошибку:

org.hibernate.QueryException: could not resolve property: name of: com.zhenyria.project.model.Shape

Существует ли какая-то возможность сортировки по полю самого enum? Может быть поможет переопределение метода compareTo() или что-то в этом роде?

Важно: сортировка должна происходить на уровне БД. Я использую пагинацию, поэтому вариант с сортировкой в коде не подходит!


Ответы (1 шт):

Автор решения: Zhenyria

Для того, чтобы сортировка работала, я реализовал конвертацию enum при сохранении в базу данных.

Начиная с JPA 2.1 имеется аннотация @Converter. Конвертер преобразует атрибут при сохранении и возвращает к изначальному типу при получении.

Код моего конвертера:

@Converter(autoApply = true)
public class ShapeTypeConverter implements AttributeConverter<ShapeType, String> {

    @Override
    public String convertToDatabaseColumn(ShapeType attribute) {
        return attribute == null ? null : attribute.getName();
    }

    @Override
    public ShapeType convertToEntityAttribute(String dbData) {
        return dbData == null
                ? null
                : Stream.of(ShapeType.values())
                .filter(t -> t.getName().equals(dbData))
                .findFirst()
                .orElseThrow(() -> new IllegalArgumentException(
                        String.format("ShapeType with name %s is not exist", dbData)));
    }
}

Теперь можно убрать аннотацию @Enumerated над полем ShapeType в сущности Shape. Если бы я не указал в аннотации autoApply=true, то пришлось бы отмечать поле аннотацией @Converter. А так Spring автоматически будет преобразовывать этот тип при любом сохранении в базу данных.

Теперь можно указывать сортировку по полю type и она будет корректно работать:

@Query("SELECT s FROM Shape s ORDER BY s.type ASC")
List<Shape> getAll();

Отсортированный вывод объектов Shape будет не такой (классическая сортировка по полю имени enum, которое сохраняется в базу данных при использовании @Enumarated(EnumType.STRING)):

{id: 1001, type: CIRCLE("Круг")},
{id: 2321, type: RECTANGLE("Прямоугольник")},
{id: 1102, type: SQUARE("Квадрат")}

а такой (здесь мы уже сохраняем не имя enum, а значение, в которое мы его конвертируем при сохранении в базу данных):

{id: 1102, type: SQUARE("Квадрат")},
{id: 1001, type: CIRCLE("Круг")},
{id: 2321, type: RECTANGLE("Прямоугольник")}
→ Ссылка