Постоянные данные, подходящие для перечислений - PullRequest
22 голосов
/ 29 января 2009

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

public enum Status {
    ACTIVE(10, "Active");
    EXPIRED(11, "Expired");
    /* other statuses... */

    /* constructors, getters, etc. */
}

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

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

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

Существует ли соглашение, которое большинство людей используют здесь? Каков опыт людей с каждым из них и есть ли другие альтернативы?

Edit:

Подумав немного, моя настоящая борьба за постоянство идет с обработкой значений идентификаторов, которые связаны со статусами в базе данных. Эти значения будут вставлены как данные по умолчанию при установке приложения. На этом этапе у них будут идентификаторы, которые можно использовать в качестве внешних ключей в других таблицах. Мне кажется, что мой код должен знать об этих идентификаторах, чтобы я мог легко получить объекты состояния и назначить их другим объектам. Что мне делать с этим? Я мог бы добавить другое поле, например, «код», для поиска элементов или просто просмотреть статусы по имени, что является icky.

Ответы [ 8 ]

8 голосов
/ 29 января 2009

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

Если вы ожидаете много значений enum, вы можете создать статическое отображение HashMap<String,MyEnum> для быстрого перевода.

Не сохраняйте фактическое имя enum (т. Е. «ACTIVE» в вашем примере), потому что оно легко реорганизовано разработчиками.

3 голосов
/ 31 марта 2009

Я использую смесь из трех описанных вами подходов ...

Использовать базу данных в качестве официального источника значений Enum. Сохраните значения в некоторой таблице «код». Каждый раз, когда вы строите, генерируйте файл класса для Enum, который будет включен в ваш проект.

Таким образом, если enum изменит значение в базе данных, ваш код будет признан недействительным и вы получите соответствующие ошибки компиляции с вашего сервера Continuous Integration. У вас есть строго типизированная привязка к вашим перечисленным значениям в базе данных, и вам не нужно беспокоиться о ручной синхронизации значений между кодом и данными.

2 голосов
/ 29 января 2009

Джошуа Блох дает превосходное объяснение перечислений и как их использовать в своей книге " Эффективная Java, второе издание " (с.147)

Там вы можете найти всевозможные приемы, как определить свои перечисления, сохранить их и как быстро отобразить их между базой данных и вашим кодом (стр. 154).

Во время выступления на Jazoon 2007 Блох дал следующие причины использовать дополнительный атрибут для отображения перечислений в поля БД и обратно: перечисление является константой, а код - нет. Чтобы убедиться, что разработчик, редактирующий источник, не может случайно нарушить отображение БД, переупорядочив перечисления или переименовав, вы должны добавить определенный атрибут (например, «dbName») в перечисление и использовать его для сопоставления.

Перечисления имеют внутренний идентификатор (который используется в операторе switch ()), но этот идентификатор изменяется при изменении порядка элементов (например, путем их сортировки или добавления элементов в середине).

Таким образом, лучшим решением является добавление метода toDB () и fromDB () и дополнительного поля. Я предлагаю использовать короткие, читаемые строки для этого нового поля, чтобы вы могли декодировать дамп базы данных, не просматривая перечисления.

1 голос
/ 06 апреля 2009

В вашей базе данных первичный ключ этой "доменной" таблицы не обязательно должен быть числом. Просто используйте varchar pk и столбец описания (для целей, связанных с вашим dba). Если вам нужно гарантировать порядок ваших значений, не полагаясь на алфавитную сортировку, просто добавьте числовой столбец с именем "order or" sequence ".

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

Если вы делаете это слишком много, создайте сценарий для генерации кода декларации / объявления.

1 голос
/ 06 апреля 2009

Что ж, у нас нет администратора базы данных, поэтому мы предпочитаем вариант 2).

Мы просто сохраняем значение Enum в базе данных, а когда мы загружаем данные из базы данных в наши доменные объекты, мы просто приводим целочисленное значение к типу enum. Это позволяет избежать головной боли при синхронизации с вариантами 1) и 3). Список определяется один раз - в коде.

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

1 голос
/ 06 апреля 2009

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

1 голос
/ 03 апреля 2009

В нескольких случаях я использовал определение перечисления в коде и представление хранилища на уровне постоянства (БД, файл и т. Д.), А затем имел методы преобразования для сопоставления их друг с другом. Эти методы преобразования необходимо использовать только при чтении или записи в постоянном хранилище, и приложение может везде использовать безопасные перечисления типов. В методах преобразования я использовал операторы switch для сопоставления. Это также позволяет генерировать исключение, если необходимо преобразовать новое или неизвестное состояние (обычно потому, что приложение или данные новее, чем другие, и были объявлены новые или дополнительные состояния).

1 голос
/ 02 апреля 2009

Хотя я не знаком с идеей «атрибутов» в Java (и не знаю, какой язык вы используете), я обычно использовал идею таблицы кодов (или таблиц, специфичных для домена) и Я приписал свои значения перечисления более конкретным данным, например, читаемым человеком строкам (например, если мое значение перечисления равно NewStudent, я бы приписал его «New Student» в качестве отображаемого значения). Затем я использую Reflection для проверки данных в базе данных и вставки или обновления записей, чтобы привести их в соответствие с моим кодом, используя фактическое значение перечисления в качестве идентификатора ключа.

...