SQL2005:Связать таблицу с несколькими таблицами и сохранить целостность ссылок?

StackOverflow https://stackoverflow.com/questions/19516

Вопрос

Вот упрощение моей базы данных:

Table: Property
Fields: ID, Address

Table: Quote
Fields: ID, PropertyID, BespokeQuoteFields...

Table: Job
Fields: ID, PropertyID, BespokeJobFields...

Затем у нас есть другие таблицы, относящиеся к Цитировать и Работа столы индивидуально.

теперь мне нужно добавить Сообщение таблица, в которой пользователи могут записывать телефонные сообщения, оставленные клиентами относительно вакансий и предложений.

Я мог бы создать две одинаковые таблицы (ЦитатаСообщение и РаботаСообщение), но это нарушает принцип DRY и кажется беспорядочным.

я мог бы создать один Сообщение стол:

Table: Message
Fields: ID, RelationID, RelationType, OtherFields...

Но это мешает мне использовать ограничения для обеспечения ссылочной целостности.Я также могу предвидеть, что это создаст проблемы со стороны разработчиков, использующих Linq to SQL в дальнейшем.

Есть ли элегантное решение этой проблемы, или мне в конечном итоге придется что-то взломать?

Бернс

Это было полезно?

Решение

Создайте одну таблицу Message, содержащую уникальный MessageId и различные свойства, которые необходимо сохранить для сообщения.

Table: Message
Fields: Id, TimeReceived, MessageDetails, WhateverElse...

Создайте две таблицы ссылок — QuoteMessage и JobMessage.Они будут содержать всего два поля каждое: внешние ключи к цитате/заданию и сообщению.

Table: QuoteMessage
Fields: QuoteId, MessageId

Table: JobMessage
Fields: JobId, MessageId

Таким образом, вы определили свойства данных сообщения только в одном месте (что позволяет легко расширять и выполнять запросы ко всем сообщениям), но у вас также есть ссылочная целостность, связывающая котировки и вакансии с любым количеством сообщений.Действительно, и цитата, и вакансия могут быть связаны с такой же сообщение (я не уверен, соответствует ли это вашей бизнес-модели, но, по крайней мере, модель данных дает вам такую ​​возможность).

Другие советы

Единственный другой способ, который я могу придумать, - это иметь базовую таблицу сообщений с идентификатором и TypeId.Ваши подтаблицы (QuoteMessage и JobMessage) затем ссылаются на базовую таблицу как для MessageId, так и для TypeId, но также содержат ПРОВЕРКИ ОГРАНИЧЕНИЙ для обеспечения соблюдения только соответствующего MessageTypeId.

Table: Message
Fields: Id, MessageTypeId, Text, ...
Primary Key: Id, MessageTypeId
Unique: Id

Table: MessageType
Fields: Id, Name
Values: 1, "Quote" : 2, "Job"

Table: QuoteMessage
Fields: Id, MessageId, MessageTypeId, QuoteId
Constraints: MessageTypeId = 1
References: (MessageId, MessageTypeId) = (Message.Id, Message.MessageTypeId)
            QuoteId = Quote.QuoteId

Table: JobMessage
Fields: Id, MessageId, MessageTypeId, JobId
Constraints: MessageTypeId = 2
References: (MessageId, MessageTypeId) = (Message.Id, Message.MessageTypeId)
            JobId = Job.QuoteId

Что это дает вам по сравнению с таблицами JobMessage и QuoteMessage?Он присваивает Сообщению статус гражданина первого класса, так что вы можете читать все Сообщения из одной таблицы.Взамен ваш путь запроса от сообщения к соответствующему предложению или заданию находится на расстоянии еще одного соединения.Это отчасти зависит от потока вашего приложения, является ли это хорошим компромиссом или нет.

Что касается двух одинаковых таблиц, нарушающих DRY, то я бы на этом не зацикливался.При проектировании БД речь идет не столько о DRY, сколько о нормализации.Если две модели, которые вы моделируете, имеют одинаковые атрибуты (столбцы), но на самом деле являются разными вещами (таблицами), то разумно иметь несколько таблиц со схожими схемами.Гораздо лучше, чем наоборот — смешивать разные вещи вместе.

@бернс

Ответ Йена (+1) правильный [смотрите примечание].Использование таблицы «многие ко многим» QUOTEMESSAGE присоединиться QUOTE к MESSAGE самая правильная модель, но оставит сиротой MESSAGE записи.

Это один из тех редкий случаи, когда можно использовать триггер.Однако необходимо соблюдать осторожность, чтобы гарантировать, что единственный MESSAGE запись не может быть связана как с QUOTE и JOB.

create trigger quotemessage_trg
on quotemessage
for delete
as
begin

delete 
from [message] 
where [message].[msg_id] in 
    (select [msg_id] from Deleted);

end

Примечание для Яна: я думаю, что в определении таблицы допущена опечатка. JobMessage, где должны быть столбцы JobId, MessageId (?).Я бы отредактировал вашу цитату, но мне может потребоваться несколько лет, чтобы добиться такого уровня репутации!

Почему бы просто не иметь в таблице сообщений поля QuoteId и JobId?Или сообщение должно касаться либо предложения, либо вакансии, а не того и другого?

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top