Возможно ли сделать сортировку в 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 шт):
Для того, чтобы сортировка работала, я реализовал конвертацию 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("Прямоугольник")}