У меня есть простой дизайн для пользовательских настроек, и он работает.В основном, есть настройки, созданные внутри, и у каждого пользователя может быть значение для данного параметра.
Вот оно:
CREATE TABLE IF NOT EXISTS setting (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
label VARCHAR(191) NOT NULL,
key VARCHAR(191) NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS user_setting (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT(10) UNSIGNED NOT NULL,
setting_id INT(10) UNSIGNED NOT NULL,
val VARCHAR(191) NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE INDEX idx_user_id_and_setting_id (user_id, setting_id),
CONSTRAINT fk_user_setting_user_id FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE,
CONSTRAINT fk_user_setting_setting_id FOREIGN KEY (setting_id) REFERENCES setting (id) ON DELETE CASCADE
);
Запрос на вставку значения в вышеприведенную схему будет выглядеть следующим образом:
INSERT INTO user_setting (user_id, setting_id, val)
VALUES (?, ?, ?)
ON DUPLICATE KEY UPDATE val = VALUES(val)
И для получения значений для пользователя, вы можете сделать что-то вроде этого:
SELECT setting.*, user_setting.*
FROM setting
INNER JOIN user_setting
ON user_setting.user_id = ?
AND user_setting.setting_id = setting.id
Моя проблема в том, что сейчас значение для каждого параметра должно быть VARCHAR
, и это не идеально, потому что в некоторых случаях параметр может быть представлен какфлажок в пользовательском интерфейсе, или что-то еще, что требует более конкретного типа.Я не хочу использовать жестко закодированные значения, такие как «истина» и «ложь» в подобных ситуациях, потому что это делает код хрупким.Я бы предпочел проверить конкретный логический тип.
Так что это мое предлагаемое решение.
CREATE TABLE IF NOT EXISTS setting (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
label VARCHAR(191) NOT NULL,
key VARCHAR(191) NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS datatype_bool (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
val TINYINT(1) NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id)
);
CREATE TABLE IF NOT EXISTS setting_datatype_bool (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
setting_id INT(10) UNSIGNED NOT NULL,
datatype_bool_id INT(10) UNSIGNED NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE INDEX idx_steting_id_and_datatype_bool_id (user_id, datatype_bool_id),
CONSTRAINT fk_setting_datatype_bool_user_id FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE,
CONSTRAINT fk_setting_datatype_bool_datatype_id FOREIGN KEY (datatype_id) REFERENCES setting_datatype_bool (id) ON DELETE CASCADE
);
CREATE TABLE IF NOT EXISTS user_setting (
id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
user_id INT(10) UNSIGNED NOT NULL,
setting_id INT(10) UNSIGNED NOT NULL,
created_at TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP,
updated_at TIMESTAMP NULL DEFAULT NULL ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (id),
UNIQUE INDEX idx_user_id_and_setting_id (user_id, setting_id),
CONSTRAINT fk_user_setting_user_id FOREIGN KEY (user_id) REFERENCES user (id) ON DELETE CASCADE,
CONSTRAINT fk_user_setting_setting_id FOREIGN KEY (setting_id) REFERENCES setting (id) ON DELETE CASCADE
);
Обратите внимание на новые таблицы datatype_bool
и setting_datatype
.Идея состоит в том, что данному параметру может быть назначен тип данных (в данном случае, логический тип данных - я мог бы создать больше таблиц, представляющих другие типы данных), и значение этого параметра будет сохранено в таблице типов данных.
На самом деле я еще не тестировал его, поэтому у меня нет запросов для этого варианта (хотя это будет несколько похоже на первый набор запросов), но теоретически это похоже на работу.
Мне было просто интересно, приходилось ли кому-то делать что-то подобное, и / или есть ли у кого-то мнение по этому проекту.
Спасибо!