SQL2005:将表链接到多个表并保留Ref完整性?


3

这里是我的数据库的简化:

Table: Property 
Fields: ID, Address 

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

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

然后我们有涉及报价工作单独表等表格。

我现在需要添加一个消息表,用户可以记录客户留下的有关工作和报价的电话留言。

我可以创建两个相同的表(QuoteMessageJobMessage),而这违反了DRY本金,似乎凌乱。

我可以创建一个消息表:

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

但这阻止我从使用约束强制执行我的引用完整性。我也可以预见它会在后面使用Linq to SQL创建开发方面的问题。

有没有这个问题的优雅解决方案,或者我最终将不得不一起破解一些东西?

伯恩斯

4

创建一个信息表,包含了独特的MessageId,你需要存储的消息的各种属性。

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

创建两个链接表 - QuoteMessage和JobMessage。这些将只包含两个字段,即引用/作业和消息的外键。

Table: QuoteMessage 
Fields: QuoteId, MessageId 

Table: JobMessage 
Fields: JobId, MessageId 

这样你只在一个地方定义的消息的数据属性(使其易于扩展,并在所有邮件查询),但你也有参照完整性连接行情和乔布斯任何数量的消息。事实上,报价和工作都可以链接到相同的消息(我不确定这是否适合您的商业模式,但至少数据模型为您提供了选项)。


1

关于我能想到的唯一的另一种方式是拥有一个基本消息表,同时包含一个Id和一个TypeId。然后,您的子表(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表相比,这会买什么?它会将消息提升为第一级公民,以便您可以读取单个表中的所有消息。作为交换,从消息到它相关的报价或工作的查询路径还有1个加入。它的类型取决于你的应用程序流是否是一个很好的折衷。

至于两个相同的表违反干 - 我不会挂在那。在数据库设计中,它不太关于DRY,更多的是关于规范化。如果你正在建模的两件事物具有相同的属性(列),但实际上是不同的事物(表格) - 那么有多个具有相似模式的表格是合理的。远远好于将不同的东西放在一起。


1

@burns

伊恩的回答(+1)是正确的[参阅注]。使用多对多表QUOTEMESSAGE加入QUOTEMESSAGE是最正确的模式,但会留下孤立的MESSAGE记录。

这是其中之一罕见可以使用触发器的情况。但是,需要注意确保单个MESSAGE记录不能同时与QUOTEJOB相关联。

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两个字段?或者,消息必须是关于报价还是工作,而不是两者?