Способы сохранения перечислений в базе данных

Как лучше всего сохранять перечисления в базе данных?

Я знаю, что Java предоставляет методы name() и valueOf() для преобразования значений перечисления в строку и обратно. Но есть ли другие (гибкие) варианты хранения этих значений?

Есть ли умный способ превратить перечисления в уникальные числа (ordinal() небезопасно использовать)?

Обновлять:

Спасибо за все отличные и быстрые ответы! Как я и подозревал.

Однако примечание к «инструментарию»; Это один способ. Проблема в том, что мне пришлось бы добавить одни и те же методы к каждому создаваемому мной типу Enum. Это много дублированного кода, и на данный момент Java не поддерживает никаких решений для этого (перечисление Java не может расширять другие классы).

Почему использование ordinal () небезопасно?

Michael Myers 23.10.2008 18:11

Потому что любые перечисляющие дополнения потом надо ставить в конец. Ничего не подозревающему разработчику легко все испортить и вызвать хаос

oxbow_lakes 23.10.2008 18:23

Понятно. Думаю, это хорошо, что я мало занимаюсь базами данных, потому что, вероятно, я бы не подумал об этом, пока не стало слишком поздно.

Michael Myers 23.10.2008 20:36

Что за база данных? MySQL имеет тип enum, но я не думаю, что это стандартный ANSI SQL.

Sherm Pendley 23.10.2008 18:19

Обратитесь к softwareengineering.stackexchange.com/questions/298472/…

Kishan Vaishnav 16.03.2020 08:09
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
128
5
108 335
11
Перейти к ответу Данный вопрос помечен как решенный

Ответы 11

Я бы сказал, что единственный безопасный механизм здесь - использовать значение String name(). При записи в БД вы мог используете sproc для вставки значения, а при чтении используете View. Таким образом, если перечисления изменяются, существует уровень косвенности в sproc / view, чтобы иметь возможность представить данные как значение перечисления без «навязывания» этого БД.

Я с большим успехом использую гибридный подход вашего решения и решения @Ian Boyd. Спасибо за совет!

technomalogical 13.07.2009 18:04
Ответ принят как подходящий

Мы никогда больше храним перечисления как числовые порядковые значения; это затрудняет отладку и поддержку. Мы сохраняем фактическое значение перечисления, преобразованное в строку:

public enum Suit { Spade, Heart, Diamond, Club }

Suit theSuit = Suit.Heart;

szQuery = "INSERT INTO Customers (Name, Suit) " +
          "VALUES ('Ian Boyd', %s)".format(theSuit.name());

а затем прочитайте:

Suit theSuit = Suit.valueOf(reader["Suit"]);

Проблема заключалась в том, что раньше смотрели на Enterprise Manager и пытались расшифровать:

Name                Suit
==================  ==========
Shelby Jackson      2
Ian Boyd            1

стихи

Name                Suit
==================  ==========
Shelby Jackson      Diamond
Ian Boyd            Heart

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

Да, он занимает больше места, но имена членов перечисления короткие, а жесткие диски дешевы, и гораздо больше стоит помочь, когда у вас возникнут проблемы.

Кроме того, если вы используете числовые значения, вы привязаны к ним. Вы не можете аккуратно вставить или переставить элементы без принудительного использования старых числовых значений. Например, изменение перечисления Suit на:

public enum Suit { Unknown, Heart, Club, Diamond, Spade }

должно было стать:

public enum Suit { 
      Unknown = 4,
      Heart = 1,
      Club = 3,
      Diamond = 2,
      Spade = 0 }

чтобы сохранить прежние числовые значения, хранящиеся в базе данных.

Как их отсортировать в базе

Возникает вопрос: допустим, я хотел упорядочить значения. Некоторые люди могут захотеть отсортировать их по порядковому номеру перечисления. Конечно, упорядочивать карты по числовому значению перечисления бессмысленно:

SELECT Suit FROM Cards
ORDER BY SuitID; --where SuitID is integer value(4,1,3,2,0)

Suit
------
Spade
Heart
Diamond
Club
Unknown

Это не тот порядок, который нам нужен - мы хотим, чтобы они располагались в порядке перечисления:

SELECT Suit FROM Cards
ORDER BY CASE SuitID OF
    WHEN 4 THEN 0 --Unknown first
    WHEN 1 THEN 1 --Heart
    WHEN 3 THEN 2 --Club
    WHEN 2 THEN 3 --Diamond
    WHEN 0 THEN 4 --Spade
    ELSE 999 END

Та же работа, которая требуется при сохранении целочисленных значений, требуется при сохранении строк:

SELECT Suit FROM Cards
ORDER BY Suit; --where Suit is an enum name

Suit
-------
Club
Diamond
Heart
Spade
Unknown

Но это не тот порядок, который нам нужен - мы хотим, чтобы они были в порядке перечисления:

SELECT Suit FROM Cards
ORDER BY CASE Suit OF
    WHEN 'Unknown' THEN 0
    WHEN 'Heart'   THEN 1
    WHEN 'Club'    THEN 2
    WHEN 'Diamond' THEN 3
    WHEN 'Space'   THEN 4
    ELSE 999 END

Я считаю, что такое ранжирование относится к пользовательскому интерфейсу. Если вы сортируете элементы на основе их значения перечисления: вы делаете что-то не так.

Но если бы вы действительно этого хотели, я бы создал таблицу размеров Suits:

| Suit       | SuitID       | Rank          | Color  |
|------------|--------------|---------------|--------|
| Unknown    | 4            | 0             | NULL   |
| Heart      | 1            | 1             | Red    |
| Club       | 3            | 2             | Black  |
| Diamond    | 2            | 3             | Red    |
| Spade      | 0            | 4             | Black  |

Таким образом, если вы хотите изменить свои карты для использования Поцелуи королей Новый порядок колоды, вы можете изменить его для отображения, не выбрасывая все свои данные:

| Suit       | SuitID       | Rank          | Color  | CardOrder |
|------------|--------------|---------------|--------|-----------|
| Unknown    | 4            | 0             | NULL   | NULL      |
| Spade      | 0            | 1             | Black  | 1         |
| Diamond    | 2            | 2             | Red    | 1         |
| Club       | 3            | 3             | Black  | -1        |
| Heart      | 1            | 4             | Red    | -1        |

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

SELECT Cards.Suit 
FROM Cards
   INNER JOIN Suits ON Cards.Suit = Suits.Suit
ORDER BY Suits.Rank, 
   Card.Rank*Suits.CardOrder

toString часто переопределяется для предоставления отображаемого значения. name () - лучший выбор, поскольку по определению является аналогом valueOf ()

ddimitrov 23.10.2008 18:40

Стоит отметить, что классы перечисления могут быть расширены, и вы можете добавлять поля / методы. Я использовал это для создания перечислений, значения которых соответствуют битовым полям (1,2,4,8 ...), чтобы их можно было объединить вместе.

basszero 23.10.2008 22:06

Что это за метод name (), о котором вы говорите? Что это за метод valueOf (), о котором вы говорите? Единственный способ, который я могу найти для преобразования члена перечисления в строку, - это использовать метод .ToString () переменной перечисления.

Ian Boyd 24.10.2008 00:22

@ anonymousstackoverflowuser.openid.org: см. java.sun.com/j2se/1.5.0/docs/api/java/lang/Enum.html#name ()

flicken 24.10.2008 01:45

Отличная реализация и ответ. Большое спасибо за совет

Helios 28.12.2008 11:03

Я категорически не согласен с этим, если требуется постоянство перечисления, тогда не следует сохранять имена. что касается обратного чтения, это еще проще со значением вместо имени, можно просто привести его к типу SomeEnum enum1 = (SomeEnum) 2;

mamu 03.09.2009 07:49

mamu: Что происходит, когда меняются числовые эквиваленты?

Ian Boyd 04.09.2009 19:34

@basszero Если в .Net, для флагов вы хотите использовать атрибут [Flags]: msdn.microsoft.com/en-us/library/…

xanadont 06.03.2010 01:01

Еще одно голосование за имена, и мы смогли запустить дельта-скрипты для преобразования старых числовых значений в новые, основанные на именах (используя MySQL, так что это помогло).

Nick Spacek 01.12.2011 17:26

Я бы отговорил любого, кто использует этот подход. Привязка к строковому представлению ограничивает гибкость кода и рефакторинг. Лучше использовать уникальные идентификаторы. Кроме того, хранение строк тратит впустую место для хранения.

Tautvydas 18.04.2014 22:57

и если нужно запросить перечисление, вы можете использовать Enum.valueOf (Suit .class, c.getString (c.getColumnIndex ("Suit")))

Omid Aminiva 24.11.2015 21:13

А как насчет сортировки? Если я хочу отсортировать результаты запроса по сохраненному перечислению, при выборе строкового представления оно будет неявно определяться именами перечисления, тогда как если мы реализуем int-значение для каждого значения перечисления, порядок остается на усмотрение программист.

SebastianRiemer 23.08.2018 09:45

@SebastianRiemer Порядок не предоставляется программисту. Если программист хотел вставить новое значение перечисления посередине: я не могу; не без нарушения всех существующих ценностей. Но предположим, что программист по ошибке сохранил значения int перечисления и то, как вы хотели выполнить сортировку. Если я хочу отсортировать результаты в запросе, но у меня есть доступ только к соответствующему значению int: как мне это сделать? Просто: ORDER BY CASE WidgetID WHEN 1 THEN 1 WHEN 2 THEN 3 WHEN 3 THEN 2 END. То же самое и по имени.

Ian Boyd 23.08.2018 21:13

Чтобы пояснить, рассмотрим этот пример, перечисление со следующими значениями: яблоко, банан, грейпфрут, апельсин; при использовании имени мы можем сортировать ASC или DESC; ASC: яблоко, банан, грейпфрут, апельсин; DESC: апельсин, грейпфрут, банан, яблоко; тогда как, если я решу дать им выделенное целочисленное значение (с помощью конструктора и поля члена типа int), например: грейпфрут (1), банан (2), апельсин (3), яблоко (4), я могу выбрать, какое заказ я хочу подать заявку; вставка новых значений не рассматривается в моем комментарии, и этот пример

SebastianRiemer 24.08.2018 09:44

@SebastianRiemer Да, если вы вставляете строки: вы не можете сортировать их как целые числа.

Ian Boyd 24.08.2018 22:18

В вашем примере Suit theSuit = Suit.valueOf (reader ["Suit"]); вы, вероятно, имели в виду Suit theSuit = Suit.valueOf (reader ["Spade"]); или что-л.

Andrey M. Stepanov 16.01.2019 16:37

@ AndreyM.Stepanov В базе данных нет столбца с именем Spade

Ian Boyd 16.01.2019 18:33

Я согласен с этим решением, потому что оно улучшает читаемость. Я также согласен, что пространство для базы данных здесь не проблема. Однако я удивлен, что никто не обсуждал тот факт, что фильтрация с помощью INT быстрее, чем фильтрация с помощью varchar (50). Это для меня единственное слабое место данного решения.

Luis Gouveia 21.10.2019 13:53

@LuisGouveia Мне было бы любопытно увидеть систему баз данных, которая имеет что-то большее, чем теоретические проблемы с производительностью, фильтрующие на varchar(50), а не на int.

Ian Boyd 21.10.2019 17:05

@IanBoyd, не принимай это на свой счет. Как я уже сказал, ваше решение - лучшее. Однако, если вы сомневаетесь в моем комментарии, вы можете увидеть следующий принятый ответ: stackoverflow.com/questions/2346920/…

Luis Gouveia 21.10.2019 17:24

@LuisGouveia Я не сомневался в разнице теоретический. Я смотрел на разницу практичный. Другими словами: это преждевременная микрооптимизация, дополнительное время которой, как мы говорим, «в шуме». См. Другой ответ - с реальными тестами (stackoverflow.com/a/39650204/12597).

Ian Boyd 21.10.2019 17:52

@IanBoyd, я согласен с вами, разница небольшая, но она незначительна, если размеры столбцов аналогичны, как в примере, который вы мне показываете. Однако код может легко использовать varchar (50) - 54 байта, что несравнимо с bigint - 8 байтов. Я считаю, что потраченное время удвоится (или больше), если в приведенном примере мы будем использовать строку из 50 символов, но, пожалуйста, скажите мне, если вы считаете, что я ошибаюсь.

Luis Gouveia 22.10.2019 17:23

@LuisGouveia Я согласен с вами, что время может удвоиться. Вызывает запрос, в котором 12.37 ms вместо этого принимает 12.3702 ms. Вот что я имею в виду под "в шуме". Вы снова запускаете запрос, и он принимает 13.29 ms или 11.36 ms. Другими словами, случайность планировщика потоков резко заглушит любую теоретически имеющуюся микрооптимизацию, которая никоим образом не видна никому и никогда.

Ian Boyd 22.10.2019 17:31

@IanBoyd, я понимаю твою точку зрения. Я думал, что разница небольшая, но не незначительная. Ваша точка зрения ясна: разница на самом деле ничтожна. Спасибо! Я думаю, что вся суть нашего обсуждения была возобновлена ​​в этой ветке и принятом ответе: stackoverflow.com/questions/183201/…

Luis Gouveia 22.10.2019 17:36

Кто-нибудь когда-нибудь задумывался о том, что младший может делать в этом коде, не зная? Изменение порядка перечислений кажется безобидным и вряд ли будет замечено при проверке кода. Изменение существующего имени ENUM, которое, как известно, хранится в базе данных, будет явным при проверке кода и будет рассмотрено. В этом случае нужно больше думать о ремонтопригодности, потому что обратная сторона неправильного типа ENUM может быть катастрофической. Особенно если обновление выпущено, и новые данные (с новыми порядковыми номерами) смешаны со старыми данными (с предыдущими порядковыми номерами), удачи в исправлении!

Zoidberg 13.12.2019 20:09

Я также хотел бы добавить, что ORM обычно даже не ЗАГРУЖАЕТ существующие данные с несоответствующим именем перечисления, и вы сразу узнаете, если имя перечисления изменится, когда оно перейдет в производство, где, поскольку порядковое изменение может гудеть незаметно причиняя непередаваемый ущерб вашим данным.

Zoidberg 13.12.2019 20:12

Как вы говорите, порядковый номер - это немного рискованно. Рассмотрим, например:

public enum Boolean {
    TRUE, FALSE
}

public class BooleanTest {
    @Test
    public void testEnum() {
        assertEquals(0, Boolean.TRUE.ordinal());
        assertEquals(1, Boolean.FALSE.ordinal());
    }
}

Если вы сохранили это как порядковые номера, у вас могут быть такие строки, как:

> SELECT STATEMENT, TRUTH FROM CALL_MY_BLUFF

"Alice is a boy"      1
"Graham is a boy"     0

Но что произойдет, если вы обновите логическое значение?

public enum Boolean {
    TRUE, FILE_NOT_FOUND, FALSE
}

Это означает, что вся ваша ложь будет неверно истолкована как «файл не найден».

Лучше просто использовать строковое представление

Мы просто сохраняем само имя перечисления - оно более читабельно.

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

public enum EmailStatus {
    EMAIL_NEW('N'), EMAIL_SENT('S'), EMAIL_FAILED('F'), EMAIL_SKIPPED('K'), UNDEFINED('-');

    private char dbChar = '-';

    EmailStatus(char statusChar) {
        this.dbChar = statusChar;
    }

    public char statusChar() {
        return dbChar;
    }

    public static EmailStatus getFromStatusChar(char statusChar) {
        switch (statusChar) {
        case 'N':
            return EMAIL_NEW;
        case 'S':
            return EMAIL_SENT;
        case 'F':
            return EMAIL_FAILED;
        case 'K':
            return EMAIL_SKIPPED;
        default:
            return UNDEFINED;
        }
    }
}

и когда у вас много значений, вам нужно иметь Map внутри вашего перечисления, чтобы этот метод getFromXYZ был небольшим.

Если вы не хотите поддерживать оператор switch и можете гарантировать, что dbChar уникален, вы можете использовать что-то вроде: public static EmailStatus getFromStatusChar (char statusChar) {return Arrays.stream (EmailStatus.values ​​()) .filter (e -> e.statusChar () == statusChar) .findFirst () .orElse (НЕ ОПРЕДЕЛЕННО); }

Kuchi 24.11.2016 12:51

Для большой базы данных я не хочу терять преимущества числового представления в размере и скорости. Я часто получаю таблицу базы данных, представляющую Enum.

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

SELECT reftable.* FROM reftable
  LEFT JOIN enumtable ON reftable.enum_ref_id = enumtable.enum_id
WHERE enumtable.enum_id IS NULL;

Другая половина этого решения - написать некоторый тестовый код, который проверяет, что перечисление Java и таблица перечисления базы данных имеют одинаковое содержимое. Это оставлено читателю в качестве упражнения.

Скажем, средняя длина имени перечисления составляет 7 символов. Ваш enumID состоит из четырех байтов, поэтому у вас есть дополнительные три байта на строку, используя имена. 3 байта x 1 миллион строк составляют 3 МБ.

Ian Boyd 01.12.2011 19:06

@IanBoyd: Но enumId, безусловно, умещается в два байта (более длинные перечисления невозможны в Java), и большинство из них умещается в одном байте (который поддерживается некоторыми БД). Экономия места незначительна, но более быстрое сравнение и фиксированная длина должны помочь.

maaartinus 24.01.2014 17:23

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

   public static String getSerializedForm(Enum<?> enumVal) {
        String name = enumVal.name();
        // possibly quote value?
        return name;
    }

    public static <E extends Enum<E>> E deserialize(Class<E> enumType, String dbVal) {
        // possibly handle unknown values, below throws IllegalArgEx
        return Enum.valueOf(enumType, dbVal.trim());
    }

    // Sample use:
    String dbVal = getSerializedForm(Suit.SPADE);
    // save dbVal to db in larger insert/update ...
    Suit suit = deserialize(Suit.class, dbVal);

Приятно использовать это со значением перечисления по умолчанию, чтобы вернуться к десериализации. Например, поймайте IllegalArgEx и верните Suit.None.

Jason 13.10.2009 22:21

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

Таблица костюмов:

suit_id suit_name
1       Clubs
2       Hearts
3       Spades
4       Diamonds

Таблица игроков

player_name suit_id
Ian Boyd           4
Shelby Lake        2
  1. Если вы когда-либо реорганизуете свое перечисление, чтобы оно было классами с поведением (например, приоритетом), ваша база данных уже правильно моделирует его.
  2. Ваш администратор базы данных счастлив, потому что ваша схема нормализована (хранит одно целое число для каждого игрока, а не целую строку, в которой могут быть опечатки, а могут и нет).
  3. Значения вашей базы данных (suit_id) не зависят от вашего значения перечисления, что также помогает вам работать с данными на других языках.

Хотя я согласен, что это хорошо, если его нормализовать и ограничить в БД, это вызывает обновления в двух местах для добавления нового значения (код и db), что может вызвать дополнительные накладные расходы. Кроме того, орфографические ошибки должны отсутствовать, если все обновления выполняются программно из имени Enum.

Jason 13.10.2009 22:23

Я согласен с комментарием выше. Альтернативным механизмом принуждения на уровне базы данных может быть запись триггера ограничения, который отклоняет вставки или обновления, которые пытаются использовать недопустимое значение.

Steve Perkins 21.06.2012 20:11

Зачем мне указывать одну и ту же информацию в двух местах? Оба в КОДЕ public enum foo {bar} и CREATE TABLE foo (name varchar); могут легко рассинхронизироваться.

ebyrob 11.11.2016 19:17

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

afk5min 01.06.2017 20:51

Несколько значений с отношением ИЛИ для одного поля перечисления. Концепция .NET с хранением типов перечислений в базе данных, таких как byte или int, и использованием FlagsAttribute в вашем коде.

http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx

Весь мой опыт подсказывает мне, что самый безопасный способ сохранения перечислений в любом месте - это использовать дополнительное значение кода или идентификатор (своего рода эволюция ответа @jeebee). Это может быть хорошим примером идеи:

enum Race {
    HUMAN ("human"),
    ELF ("elf"),
    DWARF ("dwarf");

    private final String code;

    private Race(String code) {
        this.code = code;
    }

    public String getCode() {
        return code;
    }
}

Теперь вы можете использовать любое постоянство, ссылаясь на константы перечисления по коду. Даже если вы решите изменить некоторые имена констант, вы всегда можете сохранить значение кода (например, с DWARF("dwarf") на GNOME("dwarf")).

Хорошо, погрузимся глубже в эту концепцию. Вот некоторый служебный метод, который поможет вам найти любое значение перечисления, но сначала давайте расширим наш подход.

interface CodeValue {
    String getCode();
}

И пусть наше перечисление реализует это:

enum Race implement CodeValue {...}

Пришло время магического метода поиска:

static <T extends Enum & CodeValue> T resolveByCode(Class<T> enumClass, String code) {
    T[] enumConstants = enumClass.getEnumConstants();
    for (T entry : enumConstants) {
        if (entry.getCode().equals(code)) return entry;
    }
    // In case we failed to find it, return null.
    // I'd recommend you make some log record here to get notified about wrong logic, perhaps.
    return null;
}

И используйте его как амулет: Race race = resolveByCode(Race.class, "elf")

Я столкнулся с той же проблемой, когда моя цель - сохранить значение Enum String в базе данных вместо порядкового значения.

Чтобы решить эту проблему, я использовал @Enumerated(EnumType.STRING), и моя цель была решена.

Например, у вас есть класс Enum:

public enum FurthitMethod {

    Apple,
    Orange,
    Lemon
}

В классе сущности определите @Enumerated(EnumType.STRING):

@Enumerated(EnumType.STRING)
@Column(name = "Fruits")
public FurthitMethod getFuritMethod() {
    return fruitMethod;
}

public void setFruitMethod(FurthitMethod authenticationMethod) {
    this.fruitMethod= fruitMethod;
}

Пока вы пытаетесь установить значение в базу данных, строковое значение будет сохранено в базе данных как «APPLE», «ORANGE» или «LEMON».

Вы можете использовать дополнительное значение в константе перечисления, которое может выжить как при изменении имени, так и при обращении к перечислениям:

public enum MyEnum {
    MyFirstValue(10),
    MyFirstAndAHalfValue(15),
    MySecondValue(20);

    public int getId() {
        return id;
    }
    public static MyEnum of(int id) {
        for (MyEnum e : values()) {
            if (id == e.id) {
                return e;
            }
        }
        return null;
    }
    MyEnum(int id) {
        this.id = id;
    }
    private final int id;
}

Чтобы получить идентификатор из перечисления:

int id = MyFirstValue.getId();

Чтобы получить перечисление из идентификатора:

MyEnum e = MyEnum.of(id);

Я предлагаю использовать значения без смысла, чтобы избежать путаницы, если имена перечислений должны быть изменены.

В приведенном выше примере я использовал вариант «базовой нумерации строк», оставляя пробелы, поэтому числа, скорее всего, останутся в том же порядке, что и перечисления.

Эта версия быстрее, чем использование вторичной таблицы, но делает систему более зависимой от кода и знания исходного кода.

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

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

Другие вопросы по теме