Как лучше всего сохранять перечисления в базе данных?
Я знаю, что Java предоставляет name()
и valueOf()
методы для преобразования значений перечисления в String и обратно. Но есть ли другие (гибкие) варианты хранения этих значений?
Есть ли умный способ превратить перечисления в уникальные числа ( ordinal()
небезопасно использовать)?
Обновить:
Спасибо за все отличные и быстрые ответы! Как я и подозревал.
Однако примечание к «инструментарию»; Это один способ. Проблема в том, что мне пришлось бы добавить одни и те же методы к каждому создаваемому мной типу Enum. Это много дублированного кода, и на данный момент Java не поддерживает никаких решений для этого (перечисление Java не может расширять другие классы).
Ответы:
Мы больше никогда не храним перечисления как числовые порядковые значения; это затрудняет отладку и поддержку. Мы сохраняем фактическое значение перечисления, преобразованное в строку:
а затем прочитайте:
Проблема заключалась в том, что раньше смотрели на Enterprise Manager и пытались расшифровать:
вирши
последнее намного проще. Первое требовало доступа к исходному коду и нахождения числовых значений, которые были присвоены членам перечисления.
Да, он занимает больше места, но имена членов перечисления короткие, а жесткие диски дешевы, и гораздо больше стоит помочь, когда у вас возникнут проблемы.
Кроме того, если вы используете числовые значения, вы привязаны к ним. Вы не можете аккуратно вставить или переставить элементы без принудительного использования старых числовых значений. Например, изменение перечисления Suit на:
должно было стать:
для сохранения устаревших числовых значений, хранящихся в базе данных.
Как их отсортировать в базе
Возникает вопрос: допустим, я хотел упорядочить значения. Некоторые люди могут захотеть отсортировать их по порядковому номеру перечисления. Конечно, упорядочивать карты по числовому значению перечисления бессмысленно:
Это не тот порядок, который нам нужен - мы хотим, чтобы они были в порядке перечисления:
Та же работа, которая требуется при сохранении целочисленных значений, требуется при сохранении строк:
Но это не тот порядок, который нам нужен - мы хотим, чтобы они были в порядке перечисления:
Я считаю, что такое ранжирование относится к пользовательскому интерфейсу. Если вы сортируете элементы на основе их значения перечисления: вы делаете что-то не так.
Но если бы вы действительно этого хотели, я бы создал
Suits
таблицу измерений:Таким образом, если вы хотите изменить свои карты, чтобы использовать новый порядок колоды Kissing Kings, вы можете изменить его для отображения, не выбрасывая все свои данные:
Теперь мы отделяем внутренние детали программирования (имя перечисления, значение перечисления) настройкой отображения, предназначенной для пользователей:
источник
12.37 ms
вместо этого принимает12.3702 ms
. Вот что я имею в виду под «в шуме» . Вы снова запускаете запрос, и он принимает13.29 ms
, или11.36 ms
. Другими словами, случайность планировщика потоков резко заглушит любую теоретически имеющуюся микрооптимизацию, которая никоим образом не видна никому и никогда.Если у вас нет особых причин для повышения производительности, чтобы избежать этого, я бы рекомендовал использовать отдельную таблицу для перечисления. Используйте целостность внешнего ключа, если только дополнительный поиск вас не убьет.
Таблица костюмов:
Таблица игроков
suit_id
) не зависят от значения вашего перечисления, что помогает вам работать с данными из других языков.источник
public enum foo {bar}
иCREATE TABLE foo (name varchar);
это может легко рассинхронизироваться.Я бы сказал, что единственный безопасный механизм здесь - использовать
name()
значение String . При записи в БД вы можете использовать sproc для вставки значения, а при чтении использовать View. Таким образом, если перечисления изменяются, существует уровень косвенности в sproc / view, чтобы иметь возможность представить данные как значение перечисления без «навязывания» этого БД.источник
Как вы говорите, порядковый номер - это немного рискованно. Рассмотрим, например:
Если вы сохранили это как порядковые номера, у вас могут быть такие строки, как:
Но что произойдет, если вы обновите Boolean?
Это означает, что вся ваша ложь будет неверно истолкована как «файл не найден».
Лучше просто использовать строковое представление
источник
Для большой базы данных я не хочу терять преимущества числового представления в размере и скорости. Я часто получаю таблицу базы данных, представляющую Enum.
Вы можете обеспечить согласованность базы данных, объявив внешний ключ - хотя в некоторых случаях может быть лучше не объявлять это как ограничение внешнего ключа, которое накладывает затраты на каждую транзакцию. Вы можете гарантировать согласованность, периодически выполняя проверку, в любое время по вашему выбору, с помощью:
Другая половина этого решения - написать некоторый тестовый код, который проверяет, что перечисление Java и таблица перечисления базы данных имеют одинаковое содержимое. Это оставлено в качестве упражнения для читателя.
источник
enumID
четыре байта, поэтому у вас есть дополнительные три байта на строку, используя имена. 3 байта x 1 миллион строк составляют 3 МБ.enumId
безусловно, помещается в два байта (более длинные перечисления невозможны в Java), и большинство из них умещается в одном байте (который поддерживается некоторыми БД). Экономия места незначительна, но более быстрое сравнение и фиксированная длина должны помочь.Мы просто сохраняем само имя перечисления - оно более читабельно.
Мы возились с хранением определенных значений для перечислений, где есть ограниченный набор значений, например, это перечисление с ограниченным набором статусов, которые мы используем символом для представления (более значимым, чем числовое значение):
а когда у вас много значений, вам нужно иметь Map внутри вашего перечисления, чтобы этот метод getFromXYZ был небольшим.
источник
При сохранении перечислений в виде строк в базе данных вы можете создать служебные методы для (де) сериализации любого перечисления:
источник
Весь мой опыт подсказывает мне, что самый безопасный способ сохранения перечислений в любом месте - это использовать дополнительное значение кода или идентификатор (своего рода эволюция ответа @jeebee). Это может быть хорошим примером идеи:
Теперь вы можете использовать любое постоянство, ссылаясь на константы перечисления по коду. Даже если вы решите изменить некоторые имена констант, вы всегда можете сохранить значение кода (например,
DWARF("dwarf")
вGNOME("dwarf")
)Хорошо, погрузимся глубже в эту концепцию. Вот некоторый служебный метод, который поможет вам найти любое значение перечисления, но сначала давайте расширим наш подход.
И пусть наше перечисление реализует это:
Пришло время магического метода поиска:
И используйте это как оберег:
Race race = resolveByCode(Race.class, "elf")
источник
Я столкнулся с той же проблемой, когда моя цель - сохранить значение Enum String в базе данных вместо порядкового значения.
Чтобы
@Enumerated(EnumType.STRING)
решить эту проблему, я использовал, и моя цель была решена.Например, у вас есть
Enum
класс:В классе сущности определите
@Enumerated(EnumType.STRING)
:Пока вы пытаетесь установить значение в базу данных, строковое значение будет сохранено в базе данных как "
APPLE
", "ORANGE
" или "LEMON
".источник
Несколько значений с отношением ИЛИ для одного поля перечисления. Концепция .NET с хранением типов перечислений в базе данных, таких как byte или int, и использованием FlagsAttribute в вашем коде.
http://blogs.msdn.com/b/efdesign/archive/2011/06/29/enumeration-support-in-entity-framework.aspx
источник
Вы можете использовать дополнительное значение в константе перечисления, которое может выжить как при изменении имени, так и при использовании перечислений:
Чтобы получить идентификатор из перечисления:
Чтобы получить перечисление из идентификатора:
Я предлагаю использовать значения, не имеющие смысла, чтобы избежать путаницы, если имена перечислений необходимо изменить.
В приведенном выше примере я использовал вариант «базовой нумерации строк», оставляя пробелы, поэтому числа, скорее всего, останутся в том же порядке, что и перечисления.
Эта версия быстрее, чем использование вторичной таблицы, но делает систему более зависимой от кода и знания исходного кода.
Чтобы исправить это, вы также можете настроить таблицу с идентификаторами перечислений в базе данных. Или пойти другим путем и выбрать идентификаторы перечислений из таблицы по мере добавления в нее строк.
Замечание : всегда проверяйте, что вы не проектируете что-то, что следует хранить в таблице базы данных и поддерживать как обычный объект. Если вы можете представить, что вам нужно добавить новые константы в перечисление на этом этапе, когда вы его настраиваете, это признак того, что вам может быть лучше вместо этого создать обычный объект и таблицу.
источник