Как обрабатывать перечисления без перечисляемых полей в базе данных? - PullRequest
18 голосов
/ 17 апреля 2009

Как мне реализовать поле перечисления в базе данных, которое не поддерживает перечисления? (т.е. SQLite)

Поля должны быть легко доступны для поиска с помощью "field =?" поэтому использование любого типа сериализации данных - плохая идея.

Ответы [ 5 ]

53 голосов
/ 17 апреля 2009

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

Для простоты я могу пропустить вездесущий "id" для таблицы поиска и просто использовать фактическое значение, которое мне нужно в моей основной таблице, в качестве первичного ключа таблицы поиска. Таким образом, вам не нужно делать объединение, чтобы получить значение.

CREATE TABLE BugStatus (
  status            VARCHAR(20) PRIMARY KEY
);

INSERT INTO BugStatus (status) VALUES ('NEW'), ('OPEN'), ('FIXED');

CREATE TABLE Bugs (
  bug_id            SERIAL PRIMARY KEY,
  summary           VARCHAR(80),
  ...
  status            VARCHAR(20) NOT NULL DEFAULT 'NEW',
  FOREIGN KEY (status) REFERENCES BugStatus(status)
);

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

Другие преимущества справочной таблицы заключаются в том, что вы можете добавлять или удалять значение из списка с помощью простого INSERT или DELETE, тогда как с ENUM вы должны использовать ALTER TABLE для переопределения списка.

Также попробуйте запросить текущий список разрешенных значений в ENUM, например, чтобы заполнить список выбора в вашем пользовательском интерфейсе. Это большое раздражение! С таблицей поиска это легко: SELECT status from BugStatus.

Также вы можете добавить другие столбцы атрибутов в таблицу поиска, если вам нужно (например, чтобы отметить варианты, доступные только администраторам). В ENUM вы не можете комментировать записи; это просто простые значения.

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

CREATE TABLE Bugs (
  bug_id            SERIAL PRIMARY KEY,
  summary           VARCHAR(80),
  ...
  status            VARCHAR(20) NOT NULL
    CHECK (status IN ('NEW', 'OPEN', 'FIXED'))
);

Но это использование ограничения CHECK страдает теми же недостатками, что и ENUM: трудно изменить список значений без ALTER TABLE, сложно запросить список разрешенных значений, трудно аннотировать значения.

PS: оператор сравнения равенства в SQL является единственным =. Двойной == не имеет значения в SQL.

2 голосов
/ 17 апреля 2009

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

Если вы не хотите ПРИСОЕДИНЯТЬСЯ к поиску, сделайте ключ varchar, если СОЕДИНЕНИЯ не являются проблемой, тогда сделайте ключ INT и не присоединяйтесь, если вам не нужно искать в этом поле.

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

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

У вас есть два варианта:

  • использовать целое поле

  • используйте поле varchar

Я бы лично выступил за использование varchars, потому что вы ничего не сломаете, если измените свой enum + поля удобочитаемы, но у целых есть некоторые преимущества, а именно производительность (размер данных очевиден пример)

0 голосов
/ 17 апреля 2009

Это то, что я недавно сделал

В моем отображенном в спящем режиме POJO - я сохранил тип члена как String, и это VARCHAR в базе данных.

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

Теперь тот факт, что я использую String, инкапсулирован из всех. Для остальной части приложения - мои доменные объекты используют enum. А что касается базы данных, я использую String.

Если я пропустил ваш вопрос - прошу прощения.

0 голосов
/ 17 апреля 2009

Я бы использовал varchar. Разве это не вариант для вас?

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