【问题标题】:Modelling inheritance in a database建模数据库中的继承
【发布时间】:2013-02-13 01:49:47
【问题描述】:

对于数据库作业,我必须为学校建模一个系统。部分要求是为员工、学生和家长建模信息。

在 UML 类图中,我将其建模为这三个类是人员类型的子类型。这是因为它们都需要地址数据等信息。

我的问题是:如何在数据库中建模(mysql)?

目前的想法如下:

  1. 创建一个包含每种类型的所有信息的单一人员表,并且根据存储的类型将有很多空值。 (除非我非常令人信服地论证了这个案例,否则我怀疑这是否会被讲师接受)。
  2. 一个包含三个外键的人员表,这些外键引用了子类型,但其中两个为空 - 事实上,我什至不确定这是否有意义或可能?
  3. 根据这个wikipage about django,可以在子类型上实现主键,如下所示:

    "id" integer NOT NULL PRIMARY KEY REFERENCES "supertype" ("id")
  4. 其他一些我没有想到的...

所以对于那些以前在数据库中建模继承的人来说;你是怎么做到的?您推荐什么方法,为什么?

非常欢迎链接到文章/博客文章或以前的问题。

感谢您的宝贵时间!

更新

好的,谢谢大家的回答。我已经有一个单独的地址表,所以这不是问题。

干杯,

亚当

【问题讨论】:

  • 如果这是家庭作业,请添加家庭作业标签
  • 好的。如果我不要求人们为我做这一切,我认为可以提出与“家庭作业”相关的问题?
  • 是的,问起来完全没问题;-) 这只是一种很好的形式,可以确保人们知道这是作业,并且标记是推荐的方法。是的,不要指望人们会做这一切。

标签: database inheritance


【解决方案1】:

4 表工作人员、学生、家长和普通人。 教职员工、学生和家长都有各自指向 Person 的外键(而不是相反)。

Person 具有标识此人的子类(即员工、学生或家长)的字段。

编辑:

正如 HLGM 所指出的,地址应该存在于单独的表中,因为任何人都可能有多个地址。 (但是 - 我将不同意自己的观点 - 您可能希望故意将地址限制为每人一个,从而限制邮件列表等的选择)。

【讨论】:

  • 五个表实际上作为地址应该是一个单独的表以及人们有多个地址
  • 在继承类中将外键设为主键是否是个好主意?
  • @CaptainProton:这取决于使用情况。例如学生可能应该是唯一的,因为同一个人不能是两个不同的学生。但是,如果您的教职员工获得了两份薪水——作为管理员和作为导师——那么你可能希望该人有两个“员工”记录。
  • 我想强烈补充的一件事是...员工、学生和家长中的外键必须是“非空”。这是为了确保每个员工、学生或家长都必须有一个人存在。这就像我们创建派生类的对象时,它也会自动创建基类的对象。
【解决方案2】:

好吧,我认为所有方法都是有效的,任何因将其推到一张桌子上而打分的讲师(除非要求明确表示您不应该这样做)由于他们自己的个人意见而取消了可行的策略。

我强烈建议您查看有关 NHibernate 的文档,因为它提供了执行上述操作的不同方法。我现在将尝试效仿。

您的选择:

  • 1) 一个表,其中包含所有具有“分隔符”列的数据。此栏说明此人是什么样的人。这在简单的场景和(严重的)高性能中是可行的,因为连接会伤害太多
  • 2) 每个类的表会导致列重复但会避免再次连接,因此它简单且速度更快(尽管在大多数情况下只有一个 lil 和索引可以缓解这种情况)。
  • 3) “正确”的继承。标准化版本。你快到了,但你的钥匙在错误的地方 IMO。您的 Employee 表应该包含一个 PersonId 以便您可以执行以下操作:

    select employee.id, person.name from employee internal join person on employee.personId = person.personId

获取仅在 person 表中指定 name 的所有员工姓名。

【讨论】:

    【解决方案3】:

    我会选择#3。

    您的目标是给讲师留下深刻印象,而不是产品经理或客户。学者们往往不喜欢空值,并且可能(下意识地)惩罚您使用其他方法(依赖于空值)。

    而且你不一定需要那个 django 扩展(主键 ... 参考 ...),你可以使用普通的外键。

    【讨论】:

      【解决方案4】:

      “那么对于那些之前在数据库中建模继承的人;你是怎么做到的?你推荐什么方法,为什么? "

      方法 1 和 3 都不错。差异主要在于您的用例是什么。

      1) 适应性——哪个更容易改变?几个与父表具有 FK 关系的单独表。

      2) 性能——需要更少的连接?一张桌子。

      老鼠。没有设计可以同时实现这两者。

      此外,除了单表和 FK-to-parent 之外,还有第三种设计。

      三个单独的表和一些公共列(通常在所有子类表中复制和粘贴超类列)。这是非常灵活且易于使用的。但是,它需要三个表的联合来组装一个整体列表。

      【讨论】:

        【解决方案5】:

        OO 数据库经历相同的事情并提出几乎相同的选项。

        如果重点是在数据库中为子类建模,您可能已经按照我在真实 OO 数据库中看到的解决方案的思路进行思考(将字段留空)。

        如果没有,您可能会考虑创建一个不以这种方式使用继承的系统。

        应始终谨慎使用继承,这可能是一个非常糟糕的情况。

        一个好的指导原则是永远不要使用继承,除非您确实有代码对“父”类的字段执行不同的操作,而不是对“子”类中的同一字段执行不同的操作。如果您的类中的业务代码没有专门引用某个字段,则该字段绝对不应该导致继承。

        但同样,如果你在学校,那可能与他们试图教的内容不符......

        【讨论】:

          【解决方案6】:

          对于作业而言,“正确”的答案可能是 #3:

          Person
          PersonId Name Address1 Address2 City Country
          
          Student
          PersonId StudentId GPA Year ..
          
          Staff
          PersonId StaffId Salary ..
          
          Parent
          PersonId ParentId ParentType EmergencyContactNumber ..
          

          其中 PersonId 始终是主键,也是最后三个表中的外键。

          我喜欢这种方法,因为它可以很容易地代表同一个人担任多个角色。例如,老师也很可能是家长。

          【讨论】:

            【解决方案7】:

            我建议五张桌子 人 学生 职员 家长 地址

            为什么 - 因为人们可以有多个地址,人们也可以有多个角色,而且您想要为员工提供的信息与您需要为家长或学生存储的信息不同。

            此外,您可能希望将 name 存储为 last_name、Middle_name、first_name、Name_suffix(如 jr.),而不仅仅是 name。相信我,您会希望能够搜索 last_name!名称不是唯一的,因此您需要确保拥有唯一的代理主键。

            在尝试设计数据库之前,请阅读规范化。这是一个开始的来源: http://www.deeptraining.com/litwin/dbdesign/FundamentalsOfRelationalDatabaseDesign.aspx

            【讨论】:

              【解决方案8】:

              超类型 Person 应该这样创建:

              CREATE  TABLE Person(PersonID int primary key, Name varchar ... etc ...)
              

              所有子类型都应该这样创建:

              CREATE  TABLE IF NOT EXISTS Staffs(StaffId INT NOT NULL ,
                PRIMARY KEY (StaffId) ,  
                CONSTRAINT FK_StaffId FOREIGN KEY (StaffId) REFERENCES Person(PersonId)
                )
              
              CREATE  TABLE IF NOT EXISTS Students(StudentId INT NOT NULL ,
                PRIMARY KEY (StudentId) ,  
                CONSTRAINT FK_StudentId FOREIGN KEY (StudentId) REFERENCES Person(PersonId)
                )
              
              CREATE  TABLE IF NOT EXISTS Parents(PersonID INT NOT NULL ,
                PRIMARY KEY (PersonID ) ,  
                CONSTRAINT FK_PersonID  FOREIGN KEY (PersonID ) REFERENCES Person(PersonId)
                )
              

              子类型staff,students,parents中的外键添加两个条件:

              1. 除非相应的子类型行将被删除,否则无法删除人员行 不被删除。例如如果学生中有一个学生条目 表引用人员表,不删除学生条目 人员条目不能删除,这一点非常重要。如果学生 然后创建对象而不删除 Student 对象,我们不能 删除基本 Person 对象。

              1. 所有基类型都有外键“not null”以确保每个基 type 将始终存在基本类型。例如如果你创建 Student 对象,您必须先创建 Person 对象。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 2010-09-05
                • 2010-09-16
                • 2010-12-06
                • 1970-01-01
                • 2011-04-03
                相关资源
                最近更新 更多