Существует повторяющаяся проблема относительно полей состояния и аналогичного предопределенного набора значений.
Возьмем пример системы упорядочения с сущностью порядка, которая имеет статус, который может быть "Новый", "Прогресс", "Платный" и т.д.
Эта проблема:
Статус заказа должен быть
- хранится (в базе данных)
- обрабатывается (в бэкэнд)
- (для интерфейса API веб-сервиса)
Как выполнять эти три действия при сохранении:
- Сохраните значение статуса.
- эффективное хранилище.
Вот некоторые примеры реализации с их плюсами и минусами:
1- Таблица состояния
- База данных будет содержать таблицу состояния с идентификатором, именем
-
Таблица заказа ссылается на идентификатор состояния.
CREATE TABLE 'status' ( 'id' INT NOT NULL, 'name' VARCHAR(45) NOT NULL, PRIMARY KEY ('id')); CREATE TABLE IF NOT EXISTS 'order' ( 'id' INT NOT NULL AUTOINCREMENT, 'status_id' INT NOT NULL, PRIMARY KEY ('id'), INDEX 'order_status_idx' ('status' ASC), CONSTRAINT 'order_status_id' FOREIGN KEY ('status_id') REFERENCES 'status' ('id') ON DELETE NO ACTION ON UPDATE NO ACTION);
-
Бэкэнд-код имеет перечисление, которое дает эти предопределенные целые значения в коде
enum Status { PAID = 7; }; // While processing as action ... order.status = Status::PAID;
-
API веб-службы вернет номер статуса
order: { id: 1, status_id: 7 }
-
Код интерфейса имеет аналогичное перечисление, которое дает эти предопределенные целые значения в коде. (например, бэкэнд-код)
-
Плюсы:
- База данных четко определена и нормализована
- Минусы:
- Отображение между номером статуса и значением выполняется в трех местах, что дает пространство для человеческих ошибок и непоследовательность при определении значения определенного номера статуса.
-
status_id: 7
данные API не являются описательными, потому чтоstatus_id: 7
не дает конкретного значения, потому что он не включает значениеstatus_id: 7
2- Статус ENUM
-
В базе данных таблица заказов будет содержать столбцы состояния с типом ENUM, содержащие предопределенные статусы.
CREATE TABLE IF NOT EXISTS 'order' ( 'id' INT NOT NULL AUTOINCREMENT, 'status' ENUM('PAID') NULL, PRIMARY KEY ('id'));
-
Бэкэнд-код имеет постоянные значения как артефакты кода для предопределенного статуса
enum Status { PAID = 'PAID' };
ИЛИ ЖЕ
class Status { public: static const string PAID = PAID; };
Использовать как последующее
// While processing as action ... order.status = Status::PAID;
-
API веб-службы вернет константу статуса
order: { id: 1, status: 'PAID' }
-
Код frontend будет иметь аналогичную конструкцию для предопределенных констант состояния. (например, бэкэнд-код)
-
Плюсы:
- База данных четко определена и нормализована
- Возвращенные данные из API являются описательными и предоставляют требуемое значение.
- Используемые константы статуса уже содержат их значение, что уменьшает вероятность ошибок.
- Минусы:
- Использование типа ENUM для столбца в базе данных имеет свои ограничения. Добавление новой константы статуса к этому перечислению позже с помощью команды ALTER дорого стоит специально для огромных таблиц, таких как таблица
order
.
- Использование типа ENUM для столбца в базе данных имеет свои ограничения. Добавление новой константы статуса к этому перечислению позже с помощью команды ALTER дорого стоит специально для огромных таблиц, таких как таблица
3- Мое предлагаемое решение:
-
База данных будет содержать таблицу состояний с одним полем, называемым
key
с строкой типа, которая является первичным ключом этой таблицы.CREATE TABLE 'status' ( 'key' VARCHAR(45) NOT NULL, PRIMARY KEY ('key'));
-
Таблица заказов будет содержать поле с именем
status
с строкой типа, которое ссылается наkey
поле таблицыstatus
.CREATE TABLE IF NOT EXISTS 'order' ( 'id' INT NOT NULL AUTOINCREMENT, 'status' VARCHAR(45) NOT NULL, PRIMARY KEY ('id'), INDEX 'order_status_idx' ('status' ASC), CONSTRAINT 'order_status' FOREIGN KEY ('status') REFERENCES 'status' ('key') ON DELETE NO ACTION ON UPDATE NO ACTION);
-
Бэкэнд-код имеет постоянные значения как артефакты кода для предопределенного статуса
enum Status { PAID = 'PAID' };
ИЛИ ЖЕ
class Status { public: static const string PAID = PAID; };
Использовать как последующее
// While processing as action ... order.status = Status::PAID;
-
API веб-службы вернет константу статуса
order: { id: 1, status: 'PAID' }
-
Код frontend будет иметь аналогичную конструкцию для предопределенных констант состояния. (например, бэкэнд-код)
-
Плюсы:
- База данных четко определена и нормализована
- Возвращенные данные из API являются описательными и предоставляют требуемое значение.
- Используемые константы статуса уже содержат их значение, что уменьшает вероятность ошибок.
- Добавление новой константы состояния выполняется с помощью команды INSERT в таблице состояния.
- Минусы:
- ???
Я хотел бы знать, является ли это приемлемым решением или есть лучшее решение для этой повторяющейся проблемы.
Укажите причины, по которым предлагаемое решение плохое, и почему лучше ваше решение
Спасибо.