在我想要建模的多对多关系中,我有一种或两种情况。
所以我有这些表:
Message
----
*MessageID
MessageText
Employee
----
*EmployeeID
EmployeeName
Team
----
*TeamID
TeamName
MessageTarget
----
MessageID
EmployeeID (nullable)
TeamID (nullable)
因此,Message
可以包含Employee
个列表,或Team
个列表MessageTarget
。 MessageTarget
表是否具有实现此关系的最佳方式?我可以有效地对MessageTarget
施加什么约束?我应该如何在MessageTarget
表上创建主键?
有问题的数据库是SQL Server 2008
答案 0 :(得分:2)
您提出此问题的方式似乎是Employee
是-a MessageTarget
,而Team
似乎是 MessageTarget
。
因此,Message
的{{1}}为Target
或Employee
。
在我看来,这就像SQL中的继承(或组合)问题
看看“Implementing Table Inheritance in SQL Server”。
Team
本身不是Employee
,但也许这方面的读数可以帮助您进行建模
答案 1 :(得分:2)
所以你想确保单个消息的MessageTargets都设置了employeeID或teamID,但不是两者的混合?
根据您的RDBMS,您可以创建物化视图并对其进行约束。视图看起来像
select messageId, count(employeeId), count(teamId) from messageTarget
在此,你会设置一个检查约束,确保其中一个计数为零。
或者,您可以将MessageTarget替换为两个表:EmployeeMessageTarget和TeamMessageTarget,每个表只包含一个TargetId,第一个表中包含EmployeeId,第二个表中包含TeamId。
您的Message表将获得两个新字段:EmployeeMessageTargetId和TeamMessageTargetId以及一个检查约束,确保其中至少有一个为null。如果您使两个字段都是唯一的,则可以使用* MessageTarget表中的外键。
答案 2 :(得分:1)
你也可以考虑
MessageTarget
----
MessageID
targetID (not nullable)
targetType
然后将类型设置为它应该是...
答案 3 :(得分:1)
是 - 关系通常是gen-spec模式的实例。类表继承是为gen-spec案例设计表的一种方法。
http://martinfowler.com/eaaCatalog/classTableInheritance.html
答案 4 :(得分:1)
由于员工和团队无法混合使用相同的消息,因此您需要执行以下操作:
MessageEmployee.MessageIdForEmployee
引用Message.MessageIdForEmployee
。MessageTeam.MessageIdForTeam
引用Message.MessageIdForTeam
。 Message
表上有以下约束:
CHECK (
(MessageIdForEmployee = MessageId AND MessageIdForTeam IS NULL)
OR
(MessageIdForEmployee IS NULL AND MessageIdForTeam = MessageId)
)
请注意我们如何为每种子表设置单独的联结表,并且联结表不引用父亲的PK。而是每个联结表引用单独的 UNIQUE字段。由于这些字段中只有一个可以是非NULL,因此只能将一种子项连接到任何给定的消息。
注意:将MessageId
与MessageIdForEmployee
或MessageIdForTeam
匹配并非绝对必要,但它可能会稍微简化查询。
答案 5 :(得分:0)
考虑删除MessageTarget实体中的“团队ID”字段,以便您只拥有messageId和employeeId。为了满足团队的需求(如果要求每个员工都必须是团队成员),您可以拥有另一个实体“团队消息”,其中数据库触发器将确保在插入该表时,您可以插入在团队中的每个员工的消息目标表中的行。这样,您可以方便地从每条消息链接回MessageTarget表中的员工或从“团队消息”表返回到团队。还可以在ORM框架中方便地访问,其中Employee实体只有一个List而团队也有相同的