Предположим, у меня есть 4 вида услуг, которые я предлагаю (они вряд ли будут часто меняться):
- тестирование
- дизайн
- программирование
- Другие
Предположим, у меня есть 60-80 реальных услуг, каждая из которых подпадает под одну из вышеуказанных категорий. Например, «сервис» может быть «Тестовая программа с использованием техники A» и имеет тип «Тестирование».
Я хочу закодировать их в базу данных. Я придумал несколько вариантов:
Вариант 0:
Использовать VARCHAR
напрямую для кодирования типа сервиса напрямую в виде строки
Опция 1:
Используйте базу данных enum
. Но enum это зло
Вариант 2:
использовать две таблицы:
service_line_item (id, service_type_id INT, description VARCHAR);
service_type (id, service_type VARCHAR);
Я даже могу наслаждаться ссылочной целостностью:
ALTER service_line_item
ADD FOREIGN KEY (service_type_id) REFERENCES service_type (id);
Звучит хорошо, да?
Но я все еще должен кодировать вещи и иметь дело с целыми числами, т.е. при заполнении таблицы. Или я должен создавать сложные программирования или конструкции БД при заполнении или работе с таблицей. А именно, ПРИСОЕДИНЯЕТСЯ, когда имеешь дело с базой данных напрямую, или создаешь новые объектно-ориентированные сущности на стороне программирования, и проверяю, правильно ли я ими управляю.
Вариант 3:
Не используйте enum
, не используйте две таблицы, а просто используйте целочисленный столбец
service_line_item (
id,
service_type INT, -- use 0, 1, 2, 3 (for service types)
description VARCHAR
);
Это похоже на «фальшивое перечисление», которое требует больше накладных расходов на стороне кода, например, зная это {2 == 'Programming'}
и работая с ним соответствующим образом.
Вопрос:
В настоящее время я реализовал его, используя вариант 2 , руководствуясь концепциями
- не используйте enum (вариант 1)
- избегать использования базы данных в качестве электронной таблицы (опция 0)
Но я не могу не чувствовать, что это кажется мне расточительным с точки зрения программирования и когнитивных издержек - я должен знать о двух таблицах и иметь дело с двумя таблицами против одной.
На «менее расточительный путь» я смотрю Option 3
. ИТ легче и требует для работы практически одинаковых конструкций кода (с небольшими изменениями, но сложность и структура в основном те же, но с одной таблицей)
Я полагаю, что в идеале это не всегда расточительно, и для каждого варианта есть хорошие случаи, но есть ли хорошее руководство относительно того, когда следует использовать вариант 2, а когда - вариант 3?
Когда есть только два типа (двоичный)
Чтобы добавить немного больше к этому вопросу ... в том же месте, у меня есть бинарный вариант «Стандартный» или «Исключение», который может применяться к позиции строки обслуживания. Я закодировал это, используя Вариант 3 .
Я решил не создавать новую таблицу только для хранения значений {"Стандарт", "Исключение"}. Таким образом, мой столбец просто содержит {0, 1}, и имя моего столбца называется exception
, и мой код выполняет перевод из {0, 1} => {STANDARD, EXCEPTION}
(который я закодировал как константы в языке программирования)
Пока что это не нравится ни ..... (не нравится ни вариант 2, ни вариант 3). Я нахожу вариант 2 лучше 3, но с большими издержками, и все же я не могу избежать кодирования вещей как целых чисел, независимо от того, какой вариант я использую из 2 и 3.
ORM
Чтобы добавить контекст, после прочтения ответов - я только что начал (недавно) снова использовать ORM, в моем случае Doctrine 2. После определения схемы БД с помощью аннотаций я хотел заполнить базу данных. Поскольку весь мой набор данных относительно мал, я хотел попробовать использовать программные конструкции, чтобы увидеть, как это работает.
Сначала я заполнил service_type
s, а затем service_line_item
s, так как существовал список из реальной таблицы. Таким образом, такие вещи, как «стандарт / исключение» и «тестирование» - все это строки в электронной таблице, и они должны быть закодированы в надлежащие типы перед сохранением их в БД.
Я нашел этот SO ответ: Что вы используете вместо ENUM в Doctrine2? , в котором предлагалось не использовать конструкцию enum DB, а использовать INT
поле и кодировать типы, используя конструкцию const языка программирования.
Но, как указано в приведенном выше вопросе SO, я могу избежать непосредственного использования целых чисел и использовать языковые конструкции - константы - как только они будут определены ....
Но все же .... независимо от того, как вы включите его, если я начинаю string
как тип, мне сначала нужно преобразовать его в правильный тип, даже при использовании ORM.
Так что, если, скажем $str = 'Testing';
, мне еще нужно где-то блок, который делает что-то вроде:
switch($str):
{
case 'Testing': $type = MyEntity::TESTING; break;
case 'Other': $type = MyEntity::OTHER; break;
}
Хорошо то, что вы не имеете дело с целыми числами / магическими числами [вместо того, чтобы иметь дело с закодированными постоянными величинами], но плохо то, что вы не можете автоматически извлекать вещи из базы данных без этого шага преобразования, к моему знание.
И именно это я имел в виду, говоря, что-то вроде «все еще нужно кодировать вещи и иметь дело с целыми числами». (Конечно, теперь, после комментария Окрамия, мне не нужно будет иметь дело непосредственно с целыми числами, но я буду иметь дело с именованными константами и некоторым преобразованием в / из констант по мере необходимости).