3

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

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保存关联表的名称吗?这是我和我的同龄人达成的唯一解决方案,但它似乎太“肮脏”了。保持设计的可扩展性是这里的关键,允许轻松添加新的子类

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

4

2 回答 2

7

谷歌“泛化专业化关系建模”。您将找到几篇关于如何使用关系表对 gen-spec 模式建模的优秀文章。在 SO 中已经多次提出同样的问题,但细节略有不同。

这些文章中最好的一篇将确认您决定为通用数据使用一个表,为专业数据使用单独的表。最大的不同是他们推荐使用主键和外键的方式。基本上,他们建议专用表有一个具有双重职责的单列。它作为专用表的主键,但它也是复制通用表的 PK 的外键。

维护起来有点复杂,但在加入时非常甜蜜。

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

于 2010-11-10T11:01:18.180 回答
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。只有当有卡片加 { MtgCard | 时,超类型才完整。PokemonCard } 具有相同的 CardId。在您的情况下,只能有一个子类型,可以通过简单的 CHECK 约束轻松实施。

    • 其他情况下,不止一种亚型是完全合法的。

    • 人是教师人是学生的子类型

  • 在关系数据库中,没有加入“从”或“到”(或上/下或左/右)的概念,这些概念只是为了帮助我们人类;您可以从您拥有的任何表/键开始,然后转到您需要的任何表。只有在没有关系标识符的情况下才需要中间的表(即,额外的代理项、ID 列被用作 PK而不是有意义的自然键)。

    • 在示例中,使用您的术语,您可以直接Enrollment转到Person(例如,获取 LastName)或Course(获取Name),而无需访问中间表;关系线是实心的。
      .
  • 现在,类层次结构(“Is”或“Is a”)和其他任何东西都变得简单而轻松。

标准关系数据库图的快速参考。

于 2010-11-11T03:24:33.477 回答