1

我经常看到这种设计模式,但没有给它起名字。我很想知道设计师如何称呼这种模式,以及他们如何通过合理的DB 设计来处理它。

举个简单的例子,假设学生有一个年级(1 -8)。如果学生的等级为 7 或 8,那么他们可能是荣誉学生。那么,如果您知道该位标志仅适用于特定年级的学生,那么您如何针对该学生跟踪该位标志呢?

4

2 回答 2

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 是正确的,但对于适当的关系数据库设计,通常不会通过尝试识别继承模式来解决问题。这就是面向对象的观点。关注访问模式以及代码如何获取数据总是很重要的,但是在关系数据库设计中,首先要争取数据库的规范化和灵活性,其次才是代码,因为总会有多个获取数据的代码库,并且无论访问代码有多么错误,您都希望确保数据始终有效。

于 2012-06-13T17:28:17.750 回答
0

您需要考虑类模型及其使用方式。您是否将Honors其视为 a 的布尔标志Student?比如if (grade > 6) Student.honor = true

通常,您可以将其视为继承映射的情况。将其视为Student父类,而您的子类是HonorStudent. 有多种方法可以在关系数据库中映射继承。

您可以将所有内容映射到单个表中,因为基类和子类的所有属性都会存在,但其中一些会设置为 NULL 或空。例如,如果 HonorStudent 具有属性 X,则在将 Student 映射到表时将属性 X 设置为 NULL。

另一种情况是每个具体类都有一个表。因此,您将有一个单独的表用于 Student 和 HonorStudent。

您还可以为 Student 和 HonorStudent 提供一个具有自己属性的表。子类将只有一个表,其中包含它们具有(或添加)的属性,如属性 OTHER 而不是继承的属性。继承的属性将映射到父表并使用唯一 ID 链接。

不确定这是否是您正在寻找的答案,但这就是我的看法。

于 2012-06-13T17:17:09.153 回答