表设计和类层次结构

时间:2010-11-10 08:33:29

标签: language-agnostic database-design orm class-hierarchy

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

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

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

2 个答案:

答案 0 :(得分:5)

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

这些文章中最好的将确认您决定为一般数据设置一个表,为特殊数据设置单独的表。最大的区别将是他们推荐使用主键和外键的方式。基本上,他们建议专门的表有一个单一的列,可以执行双重任务。它作为专用表的主键,但它也是一个重复广义表的PK的外键。

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

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

答案 1 :(得分:3)

基本上没有。

忘记类层次结构,存储模型以及特定于您的应用和特定应用语言的任何内容。除非您想将RDb用作文件的存储位置,否则为从属服务器。

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

您需要的结构是普通的子类型超类型。这些是关系数据库术语,已在RM中存在超过30年,在关系数据库产品中已存在超过23年。无需称他们为有趣的新名字。除了癌症肿瘤外,Wiki不是学术参考。

鉴于您的表格作为起点非常正确(您已自动规范化),您需要:

  • 将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约束强制执行。

    • other cases中,多个子类型非常合法。

    • 人是教师人是学生

    • 的子类型
  • 在关系数据库中,没有加入“从”或“到”(或上/下或左/右)的概念,这些概念只是为了帮助我们人类;你可以从你拥有的任何桌子/钥匙开始,然后去你需要的任何桌子。仅在没有关系标识符的情况下才需要中间的表(即,其中附加的代理,ID列用作PK 而不是有意义的自然键)。< / p>

    • 在示例中,使用您的条款,您可以 em> to 课程(获取名称)而无需访问中间表;关系线是实心的 。
  • 现在,类层次结构(“是”或“是一个”)和其他任何东西都是简单而轻松的。如果你看起来不太简单,请发一个单语句类谓词(英文),我将提供SQL。

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