Database SQL2005:将一个表链接到多个表并保持引用完整性?

Database SQL2005:将一个表链接到多个表并保持引用完整性?,database,sql-server-2005,referential-integrity,Database,Sql Server 2005,Referential Integrity,以下是我的数据库的简化: Table: Property Fields: ID, Address Table: Quote Fields: ID, PropertyID, BespokeQuoteFields... Table: Job Fields: ID, PropertyID, BespokeJobFields... 表:财产 字段:ID、地址 表:报价 字段:ID、PropertyID、BespokeQuoteFields。。。 表:工作 字段:ID、PropertyID、Bespo

以下是我的数据库的简化:

Table: Property Fields: ID, Address Table: Quote Fields: ID, PropertyID, BespokeQuoteFields... Table: Job Fields: ID, PropertyID, BespokeJobFields... 表:财产 字段:ID、地址 表:报价 字段:ID、PropertyID、BespokeQuoteFields。。。 表:工作 字段:ID、PropertyID、BespokeJobFields。。。 然后,我们还有与报价作业表相关的其他表

我现在需要添加一个Message表,用户可以在其中记录客户关于工作和报价的电话留言

我可以创建两个相同的表(QuoteMessageJobMessage),但这违反了DRY原则,看起来很混乱

我可以创建一个消息表:

Table: Message Fields: ID, RelationID, RelationType, OtherFields... 表:信息 字段:ID、RelationID、RelationType、其他字段。。。 但这阻止了我使用约束来强制我的引用完整性。我还可以预见它在以后使用LINQtoSQL开发方面会产生问题

这个问题是否有一个优雅的解决方案,或者我最终是否要一起解决一些问题


Burns

创建一个消息表,其中包含一个唯一的消息ID和需要为消息存储的各种属性

Table: Message
Fields: Id, TimeReceived, MessageDetails, WhateverElse...
创建两个链接表-QuoteMessage和JobMessage。这些字段只包含两个字段,分别是报价/作业和消息的外键

Table: QuoteMessage
Fields: QuoteId, MessageId

Table: JobMessage
Fields: JobId, MessageId

通过这种方式,您只在一个位置定义了消息的数据属性(便于扩展和跨所有消息查询),但您还具有将引号和作业链接到任意数量消息的引用完整性。事实上,Quote和Job都可以链接到同一个消息(我不确定这是否适合您的业务模型,但至少数据模型为您提供了选择)。

关于我能想到的唯一其他方法是拥有一个同时具有Id和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表相比,这给你带来了什么?它将消息提升为一等公民,以便您可以从单个表中读取所有消息。作为交换,从消息到相关报价或作业的查询路径是1个多连接。这在某种程度上取决于你的应用程序流,这是否是一个好的权衡

至于两张完全相同的桌子,我不会挂断。在DB设计中,更多的是规范化,而不是干法。如果要建模的两个对象具有相同的属性(列),但实际上是不同的对象(表),那么使用类似模式的多个表是合理的。比把不同的东西咀嚼在一起的相反方式要好得多。

@burns

伊恩的答案(+1)是正确的[见注]。使用多对多表
QUOTEMESSAGE
QUOTE
连接到
MESSAGE
是最正确的模式,但会留下孤立的
MESSAGE
记录

这是极少数可以使用触发器的情况之一。但是,需要注意确保单个
消息
记录不能同时与
报价
作业
关联

create trigger quotemessage_trg
on quotemessage
for delete
as
begin

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

end

Ian注意,我认为
JobMessage
的表定义中有一个输入错误,其中的列应该是
JobId,MessageId
(?)。我会编辑你的报价,但我可能需要几年的时间才能获得这样的声誉

为什么不在消息表中同时包含QuoteId和JobId字段?或者信息必须是关于报价或工作,而不是两者