我经常看到这种设计模式,但没有它的名称。我很想知道设计师称这种模式以及他们如何通过合理的 DB设计来实现它。
举个简单的例子,假设学生的成绩 (1-8)。如果学生的成绩为7或8,那么他们可能是荣誉学生。那么你如何跟踪学生的这个标志,知道它只适用于某些年级的学生?
答案 0 :(得分:5)
我称之为数据依赖。并非所有数据依赖关系都可以通过关系分解直接或方便地建模。使用检查约束可以很容易地处理这个:
CREATE TABLE Students (
id SERIAL PRIMARY KEY, -- for example, something else in reality
grade INTEGER NOT NULL,
honors BOOLEAN,
CONSTRAINT ensure_honors_grade
CHECK((honors IS NULL AND grade < 7) OR
(honors IS NOT NULL AND grade >= 7))
);
另一种解决方案可能是使用两个表:
CREATE TABLE Students (
id SERIAL PRIMARY KEY,
grade INTEGER NOT NULL,
CONSTRAINT id_grade_unique UNIQUE (id, grade) -- needed for FK constraint below
);
CREATE TABLE Honors (
student_id INTEGER NOT NULL,
grade INTEGER NOT NULL,
honors BOOLEAN NOT NULL,
CONSTRAINT student_fk FOREIGN KEY (student_id, grade) REFERENCES Students(id, grade),
CONSTRAINT valid_grade CHECK(grade >= 7)
);
这种替代设计更明确地说明了成绩与是否有荣誉标志之间的关系,并为7-8年级学生的进一步差异留下了空间(尽管表名应该改进)。如果你只有一个属性,荣誉布尔值,那么这可能是矫枉过正。正如@BrankoDimitrijevic所提到的,这并不强制Honors
中存在一行只是因为等级为7或8,而且你还要支付一个你不需要的索引。所以有权衡;这些肯定不是唯一两种可能的设计; Branko还建议使用触发器。
对于OO设计,@ Ryan是正确的,但对于正确的关系数据库设计,通常不会通过尝试识别继承模式来解决问题。这就是面向对象的观点。关注您的访问模式以及您的代码将如何获取数据始终是非常重要的,但在关系数据库设计中,首先要求数据库中的规范化和灵活性,以及第二个代码,因为总是会有多个代码库获取数据,并且您希望确保数据始终有效,无论访问代码有多么多。
答案 1 :(得分:0)
您需要考虑类模型及其使用方式。您是否将Honors
视为Student
的布尔标志?例如if (grade > 6) Student.honor = true
?
通常,您可以将此视为继承映射的一种情况。请将其视为Student
是父类,您的子类是HonorStudent
。有多种方法可以在关系数据库中映射继承。
您可以将所有内容映射到单个表,因为基类中的所有属性都会存在,但是其中一些属性将设置为NULL或空。例如,如果HonorStudent具有属性X,则在将Student映射到表时将属性X设置为NULL。
另一种情况是每个具体类都有一个表。所以你会为Student和HonorStudent设一个单独的表。
您还可以为Student和HonorStudent提供一个具有自己属性的表格。子类只有一个表具有他们拥有(或添加)的属性,如在属性OTHER中而不是继承的属性。继承的属性将映射到父表并链接到唯一的ID。
不确定这是否是您正在寻找的答案,但这就是我的看法。