MySQL - Отношения «многие ко многим» между тремя объектами - PullRequest
0 голосов
/ 10 апреля 2020

У меня проблемы с поиском лучшего дизайна для моих отношений «многие ко многим» в моей базе данных. Мой проект позволяет пользователям создавать то, что мы называем журналами тревоги. Тревога журнала проверит, соответствует ли данный журнал определенным критериям, и, если так, отправит сообщение на AWS SNS topi c. Что я хочу сделать, так это связать сообщения журнала с темами AWS SNS. Я также хочу связать, какой пользователь назначил этот журнал тревоги этому AWS SNS topi c.

У меня есть таблица класса XRefUserLogAlarmSNSTopi c. У него есть три внешних ключа. Цель этой таблицы состоит в том, чтобы связать, какие темы SNS связаны с какими журнальными аварийными сигналами, и указать, какой пользователь установил связь. Это кажется мне довольно грязным, и я получаю всевозможные ошибки, когда пытаюсь создать новые журналы тревоги или объединить таблицы в Spring JPA. У меня вопрос, есть ли лучшая структура базы данных для того, что я пытаюсь достичь

    UserId INT NOT NULL AUTO_INCREMENT,
    Username VARCHAR(50) NOT NULL,
    Password TEXT NOT NULL,
    Email VARCHAR(255) NOT NULL,
    Dashboard LONGTEXT NOT NULL,
    PRIMARY KEY (UserId),
    UNIQUE (Username),
    UNIQUE (Email)
);

CREATE TABLE SNSTopics (
    SNSTopicId INT NOT NULL AUTO_INCREMENT,
    TopicName VARCHAR(50) NOT NULL,
    TopicArn VARCHAR(255) NOT NULL,
    PRIMARY KEY (SNSTopicId),
    UNIQUE (TopicName),
    UNIQUE (TopicArn)
);

CREATE TABLE LogGroups (
    LogGroupId INT NOT NULL AUTO_INCREMENT,
    Name VARCHAR(255) NOT NULL,
    PRIMARY KEY (LogGroupId),
    UNIQUE (Name)
);

CREATE TABLE Keywords (
    KeywordId INT NOT NULL AUTO_INCREMENT,
    Word VARCHAR(70),
    PRIMARY KEY (KeywordId),
    UNIQUE (Word)
);

CREATE TABLE LogAlarms (
    LogAlarmId INT NOT NULL AUTO_INCREMENT,
    LogLevel VARCHAR(5) NOT NULL CHECK (LogLevel IN ('TRACE', 'DEBUG', 'INFO', 'WARN', 'ERROR')),
    Comparison VARCHAR(2) CHECK (Comparison IN ('==', '<', '<=', '>', '>=')),
    AlarmName VARCHAR(255) NOT NULL,
    KeywordRelationship CHAR(3) CHECK (KeywordRelationship IN ('ANY', 'ALL', NULL)),
    PRIMARY KEY (LogAlarmId),
    UNIQUE (AlarmName)
);

CREATE TABLE MetricAlarms (
    MetricAlarmId INT NOT NULL AUTO_INCREMENT,
    AlarmArn VARCHAR(100) NOT NULL,
    PRIMARY KEY (MetricAlarmId),
    UNIQUE (AlarmArn)
);

CREATE TABLE XRefUserMetricAlarm (
    UserMetricAlarmId INT NOT NULL AUTO_INCREMENT,
    UserId INT NOT NULL,
    MetricAlarmId INT NOT NULL,
    PRIMARY KEY (UserMetricAlarmId),
    FOREIGN KEY (UserId) REFERENCES Users(UserId) ON DELETE CASCADE,
    FOREIGN KEY (MetricAlarmId) REFERENCES MetricAlarms(MetricAlarmId) ON DELETE CASCADE,
    UNIQUE (UserId, MetricAlarmId)
);

CREATE TABLE XRefLogAlarmLogGroup (
    LogAlarmLogGroupId INT NOT NULL AUTO_INCREMENT,
    LogAlarmId INT NOT NULL,
    LogGroupId INT NOT NULL,
    PRIMARY KEY (LogAlarmLogGroupId),
    FOREIGN KEY (LogAlarmId) REFERENCES LogAlarms(LogAlarmId) ON DELETE CASCADE,
    FOREIGN KEY (LogGroupId) REFERENCES LogGroups(LogGroupId) ON DELETE CASCADE,
    UNIQUE (LogAlarmId, LogGroupId)
);

CREATE TABLE XRefLogAlarmKeyword (
    LogAlarmKeywordId INT NOT NULL AUTO_INCREMENT,
    LogAlarmId INT NOT NULL,
    KeywordId INT NOT NULL, 
    PRIMARY KEY (LogAlarmKeywordId),
    FOREIGN KEY (LogAlarmId) REFERENCES LogAlarms(LogAlarmId) ON DELETE CASCADE,
    FOREIGN KEY (KeywordId) REFERENCES Keywords(KeywordId) ON DELETE CASCADE,
    UNIQUE (LogAlarmId, KeywordId)
);

CREATE TABLE XRefUserLogAlarmSNSTopic (
    UserLogAlarmSNSTopicId INT NOT NULL AUTO_INCREMENT,
    LogAlarmId INT NOT NULL,
    SNSTopicId INT NOT NULL,
    UserId INT NOT NULL,
    PRIMARY KEY (UserLogAlarmSNSTopicId),
    FOREIGN KEY (LogAlarmId) REFERENCES LogAlarms(LogAlarmId) ON DELETE CASCADE,
    FOREIGN KEY (SNSTopicId) REFERENCES SNSTopics(SNSTopicId) ON DELETE CASCADE,
    FOREIGN KEY (UserId) REFERENCES Users(UserId) ON DELETE CASCADE,
    UNIQUE (LogAlarmId, SNSTopicId, UserId)
);```

1 Ответ

0 голосов
/ 10 апреля 2020

Чтобы соответствовать вашему описанию, ваш XRefUserLogAlarmSNSTopic неверен.

На самом деле вы не хотите связывать три объекта, а только два: вы хотите связать аварийные сигналы журнала с AWS темами SNS (которые являются двумя значениями, которые идентифицируют это отношение), и затем добавьте пользователя как атрибут к этому отношению. Хотя в этом случае этот специфицированный атрибут c относится к другому объекту, он логически не принципиально отличается от, например, отметки времени, которая хранится при создании этого отношения (этим пользователем).

Разница с вашей текущей таблицей является первичным ключом / уникальным ключом: ваша текущая таблица позволяет вам добавлять отношения между тревогой и топи c несколько раз, если их добавляют разные пользователи, так как только (alarm, topic, user) должен быть уникальным, вместо (alarm, topic) уникальный и user являющийся атрибутом этого отношения.

Я бы также подумал, если вы хотите ON DELETE CASCADE для столбца UserId. Хотя каскадирование для LogAlarmId и SNSTopicId имеет смысл, не очевидно, что вам нужно удалять все отношения при удалении пользователя, который их создал (хотя, конечно, это зависит от ваших требований). Может быть, лучше просто установить их на null. Поэтому я хотел бы предложить таблицу типа

CREATE TABLE XRefLogAlarmSNSTopic (   -- user not part of table name
    LogAlarmSNSTopicId INT NOT NULL AUTO_INCREMENT,  
    LogAlarmId INT NOT NULL,
    SNSTopicId INT NOT NULL,
    UserId INT NULL,  -- null
    PRIMARY KEY (UserLogAlarmSNSTopicId),
    FOREIGN KEY (LogAlarmId) REFERENCES LogAlarms(LogAlarmId) ON DELETE CASCADE,
    FOREIGN KEY (SNSTopicId) REFERENCES SNSTopics(SNSTopicId) ON DELETE CASCADE,
    FOREIGN KEY (UserId) REFERENCES Users(UserId) ON DELETE SET NULL,  -- set null
    UNIQUE (LogAlarmId, SNSTopicId)  -- user not part of primary key candidate
)

Очевидно также, что вы хотите , что это 3-сторонняя связь, например, каждый пользователь создает свою собственную тревогу -topi c -отношения, в этом случае ваша таблица будет правильной, просто ваше описание будет недостаточно точным.

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