表设计和类层次结构

问题描述 投票:2回答:2

希望有人可以通过示例或一些建议的阅读来阐明这个问题。 我想知道在类层次结构等效之后对表进行建模的最佳设计方法是什么。最好通过一个示例来描述:

abstract class Card{
    private $_name = '';
    private $_text = '';
}

class MtgCard extends Card{
    private $_manaCost = '';
    private $_power = 0;
    private $_toughness = 0;
    private $_loyalty = 0;
}

class PokemonCard extends Card{
    private $_energyType = '';
    private $_hp = 0;
    private $_retreatCost = 0;
}

现在,当对表进行建模以与该类层次结构同步时,我采用了非常相似的方法:

TABLE Card
  id            INT, AUTO_INCREMENT, PK
  name          VARCHAR(255)
  text          TEXT

TABLE MtgCard
  id            INT, AUTO_INCREMENT, PK
  card_id       INT, FK(card.id)
  manacost      VARCHAR(32)
  power         INT
  toughness     INT
  loyalty       INT

TABLE PokemonCard
  id            INT, AUTO_INCREMENT, PK
  card_id       INT, FK(card.id)
  hp            INT
  energytype    ENUM(...)
  retreatcost   INT

我遇到的问题是试图找出如何将每个Card记录与包含来自相应表的详细信息的记录相关联。具体来说,如何确定我应该查看哪个表。

是否应该在VARCHAR中添加Card列以保存关联表的名称?那是我和我的同伴们达成的唯一解决方案,但似乎太“肮脏”了。 保持设计的可扩展性是这里的关键,允许轻松添加新的子类

[如果有人可以提供示例或资源来显示类/表层次结构的清晰镜像方式,将不胜感激。

language-agnostic database-design orm class-hierarchy
2个回答
5
投票

Google“一般化专业化关系建模”。您将找到有关如何使用关系表对基因规格模式进行建模的一些出色文章。在SO中,相同的问题已经问了很多遍,但细节有所不同。

这些文章中的精华将确认您的决定,即要使用一张表来存储广义数据,而使用单独的表来存储特殊数据。最大的不同是他们推荐使用主键和外键的方式。基本上,他们建议专用表的一列承担双重职责。它用作专用表的主键,但它也是一个外键,它复制了通用表的PK。

这维护起来有点复杂,但是在加入时非常好。

还请记住,将新类添加到层次结构时,需要DDL。


3
投票

基本上不。

忘记类层次结构,存储模型以及您的应用程序和特定应用程序语言所特有的任何内容。除非您想将RDb用作文件的纯粹存储位置,否则不要使用从属。

如果您想要关系数据库的功能和灵活性(特别是可扩展性),那么您需要独立于任何应用程序并使用RDb原则(而不是应用程序语言要求)对其进行建模。将您的应用程序上下文保留一段时间,然后将数据库设计为数据库。了解他们。规范化(消除所有重复)。了解结构和规则,并加以实施。当您这样做时,您的查询和“映射”将变得毫不费力。不会有“阻抗”。使用正确的数据类型,不会出现不匹配的情况。

您需要的结构是普通的子类型-超类型。这些是关系数据库术语,在RM中已经存在30多年了,在关系数据库产品中已经存在了23年以上。无需称它们为有趣的新名字。维基百科不是学术参考。

鉴于您的表作为起点非常正确(已自动归一化,您需要:

  • 将Card.Id重命名为Card.CardId

  • 删除子类型的ID,它们是100%冗余的; CardId既是PK又是FK。

  • 添加识别符Card.CardType CHAR(1)或TINYINT。当CardType未知时,这将标识要与哪个子类型联接。

  • 看来您不完全了解外键的概念,因此最好先做好准备。它以简单,普通的形式在这里实现:

    ALTER TABLE MtgCard
        ADD CONSTRAINT Card_MtgCard_fk
        FOREIGN KEY (CardId)
        REFERENCES Card(CardId)
  • Card与MtgCard或PokemonCard之间的关系始终为1 :: 1。仅当有Card加{MtgCard |具有相同CardId的PokemonCard}。在您的情况下,只能有一个子类型,可以通过简单的CHECK约束轻松实施。

    • other cases中,一个以上的子类型是完全合法的。

    • 子类型有人是老师人是学生

  • 在关系数据库中,没有连接“从”或“到”(或上/下或左/右)的概念,这些概念仅用于帮助人类。您可以从拥有的任何表/键开始,然后转到所需的任何表。仅在不存在关系标识符的情况下才需要它们之间的表(即,其中additional代理,ID列用作PK 代替有意义的自然键)。

    • 在示例中,使用您的术语,您可以go直接来自注册to人员(例如,获取姓氏)或to课程(以获取姓名),而不必访问中间表;关系线是实线。。
  • 现在,类层次结构(“ Is”或“ Is a”)以及其他任何东西都变得简单而轻松。

Quick Reference到标准关系数据库图。

© www.soinside.com 2019 - 2024. All rights reserved.