Управление порядком сортировки свойств Hibernate EnumType.STRING - PullRequest
6 голосов
/ 31 августа 2010

В настоящее время мой проект использует @Enumerated(EnumType.ORDINAL), поэтому, когда я сортирую по этому столбцу, он упорядочивается по порядку в enum, который работает нормально. Но мне нужно добавить некоторые дополнительные значения к enum, которые нужно вставлять в разные места в списке значений перечисления, и их нельзя просто добавить вниз, чтобы поддерживать правильный порядок сортировки.

Если я сделаю это, моя база данных будет испорчена. Мне придется написать несколько сценариев, чтобы перевести все эти порядковые значения в правильный новый порядковый номер. Существует вероятность того, что еще статус будет добавлен позже. Поскольку мне нужно исправить все данные в базе данных, я бы хотел сделать это только один раз, поскольку это будет большая задача.

Так что я думаю о переключении на EnumType.STRING, чтобы не пришлось заново переназначать порядковые значения в базе данных. Но если я сделаю это, то как мне правильно отсортировать? Алфавитный порядок строк enum не тот, который мне нужен.

Используя приведенные ниже классы, когда я сортирую по свойству "status", результаты получаются в следующем порядке:

hql = "from Project order by status"

Development
Planning
Production

Я бы хотел, чтобы они вышли в таком порядке, без использования EnumType.ORDINAL:

Planning
Development
Production

Возможно ли это без создания таблицы для enum или добавления дополнительного столбца в класс Project? Я пробовал это, но выдает исключение:

hql = "from Project order by status.sort"

Перечисление:

public enum Status {

    PLANNING("Planning", 0),
    DEVELOPMENT("Development", 1),
    PRODUCTION("Production", 2);

    private final String name;
    private final int sort;
    private Status(String name, int sort) {
        this.name = name;
        this.sort = sort;
    }
    @Override
    public String toString() {
        return name;
    }
}

Сущность:

@Entity
public class Project {
    private Long id;
    private Status status;

    @Id
    @GeneratedValue
    public Long getId() {
        return this.id;
    }
    private void setId(Long id) {
        this.id = id;
    }
    @Enumerated(EnumType.STRING)
    public Status getStatus() {
        return status;
    }
    public void setStatus(Status status) {
        this.status = status;
    }
}

1 Ответ

7 голосов
/ 31 августа 2010

Так что я думаю о переходе на EnumType.STRING, чтобы не пришлось заново переназначать порядковые значения в базе данных.Но если я сделаю это, то как мне правильно отсортировать?Алфавитный порядок строк перечисления - это не тот порядок, который мне нужен.

Лично я полностью избегаю использования зла EnumType.ORDINAL, поскольку простое изменение порядка констант может нарушить логику персистентности.Злой.Тем не менее, EnumType.STRING действительно не всегда уместно.

В вашем случае, вот что я бы сделал (со стандартным JPA): я бы сохранил int на уровне сущности и выполнил бы преобразование перечисления в методах получения / установки.Что-то вроде этого.Во-первых, enum:

public enum Status {
    PLANNING("Planning", 100),
    DEVELOPMENT("Development", 200),
    PRODUCTION("Production", 300);

    private final String label;
    private final int code;

    private Status(String label, int code) {
        this.label = label;
        this.code = code;
    }

    public int getCode() { return this.code; }

    private static final Map<Integer,Status> map;
    static {
        map = new HashMap<Integer,Status>();
        for (Status v : Status.values()) {
            map.put(v.code, v);
        }
    }
    public static Status parse(int i) {
        return map.get(i);
    }
}

Итак, в принципе, идея состоит в том, чтобы иметь возможность получить Status его code.И мы сохраняем некоторое пространство между константами, так что добавление значений возможно (это не красиво, но, хорошо, это будет работать и должно быть безопасным в течение некоторого времени).

А затем в сущности:

@Entity
public class Project {
    private Long id;
    private int statusCode;

    @Id @GeneratedValue
    public Long getId() {
        return this.id;
    }
    private void setId(Long id) {
        this.id = id;
    }

    @Transient
    public Status getStatus () {
        return Status.parse(this.statusCode);
    }
    public void setStatus(Status status) {
        this.statusCode = status.getCode();
    }

    protected int getStatusCode() {
        return statusCode;
    }
    protected void setStatusCode(int statusCode) {
        this.statusCode = statusCode;
    }
}

Получатель / установщик для представления int защищены.Публичный геттер / сеттер занимается конверсией.

Альтернативным решением будет использование пользовательского типа (за счет переносимости).

Смежные вопросы

...