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


3

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

Table: Property 
Fields: ID, Address 

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

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

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

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

я мог бы создать две идентичные таблицы (QuoteMessage и JobMessage), но это нарушает СУХОЙ принципала и кажется грязным.

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

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

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

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

Burns

4

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

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

Создайте две таблицы ссылок - QuoteMessage и JobMessage. Они будут содержать только два поля, внешние ключи для Quote/Job и Message.

Table: QuoteMessage 
Fields: QuoteId, MessageId 

Table: JobMessage 
Fields: JobId, MessageId 

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


1

О другом, о котором я могу думать, состоит в том, чтобы иметь базовую таблицу сообщений с идентификатором и типом. Ваши подтемы (QuoteMessage и JobMessage) затем ссылаются на базовую таблицу как на MessageId, так и на TypeId, но также имеют CHECK CONSTRAINTS на них для принудительного применения только соответствующего 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 

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

Что касается 2 одинаковых таблиц, нарушающих СУХИЕ - я бы не повесил трубку. В дизайне БД речь идет не о СУХОЙ, а о нормализации. Если две вещи, которые вы моделируете, имеют одинаковые атрибуты (столбцы), но на самом деле разные вещи (таблицы) - тогда разумно иметь несколько таблиц с подобными схемами.Гораздо лучше, чем наоборот, смешивать разные вещи вместе.


1

@burns

ответ Яна (+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 (?). Я бы отредактировал вашу цитату, но мне может потребоваться несколько лет, чтобы получить такой уровень репутации!


0

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