Дилемма состояния работы
Существует повторяющаяся проблема относительно полей состояния и аналогичного предопределенного набора значений.
Возьмем пример системы упорядочения с сущностью порядка, которая имеет статус, который может быть "Новый", "Прогресс", "Платный" и т.д.
Эта проблема:
Статус заказа должен быть
- хранится (в базе данных)
- обрабатывается (в бэкэнд)
- (для интерфейса 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
.
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 в таблице состояния.
- Минусы:
Я хотел бы знать, является ли это приемлемым решением или есть лучшее решение для этой повторяющейся проблемы.
Укажите причины, по которым предлагаемое решение плохое, и почему лучше ваше решение
Спасибо.
Ответы
Ответ 1
Этот мой подход к этой проблеме:
- Я добавляю
status
столбца с string
типа в таблице orders
. - Определите константу всех ваших статусов в своем классе, чтобы вы могли легко ссылаться на них.
- Выполните правило проверки правильности создания порядка, в котором значение статуса находится в разрешенных ранее разрешениях.
Это упрощает добавление нового статуса, просто редактируя базу кода, а полученное значение для статуса по-прежнему является строкой (описательной).
Надеюсь, это ответит на ваш вопрос.
Ответ 2
Я предлагаю это:
- Сохранить в БД как статус (unsigned tinyint, char (5)).
- Идентификатор должен быть степенью 2: 1,2,4,8,...
- На внутреннем коде имя const должно быть гуманизированным, а значение - int:
const PAID = 2
- В бэкэнде вы не должны использовать conts напрямую, а использовать объект класса статуса, который будет содержать некоторые методы, такие как
value
и name
. - Этот тест класса проверит, что все его значения находятся в БД и все значения БД покрыты классом.
пространство для человеческих ошибок
Тесты придуманы, чтобы избежать человеческих ошибок.
Статусы обычно не так сложны и имеют не так много значений, чтобы с ними связываться.
Enum это зло. http://komlenic.com/244/8-reasons-why-mysqls-enum-data-type-is-evil/
По поводу вашего предложения:
База данных хорошо определена и нормализована
Нет. Это денормализовано.
Возвращенные данные из API носят описательный характер и обеспечивают требуемое значение.
Вы всегда можете использовать обертку, которая входит в таблицу статуса, чтобы получить человеческое имя.
Используемые константы состояния уже содержат их значение, что снижает вероятность ошибок.
Название Const для людей, а значения для Benders.
Добавить новую константу состояния просто с помощью команды INSERT в таблице состояния.
То же самое в первом и моем решении.