这不是一个简单的问题...SQL 数据库不擅长对类层次结构建模。
你需要一个好的 ORM。
我把一个类层次结构放在一个表中,这样做是:
首先我确保它是相关的:例如,将网络 CMS 的节点、文章等放在同一个表中是有意义的,因为这些都是同一事物的变体。
这个想法是您需要创建用于搜索、索引和进行 SQL 查询的数据库列,但您不需要将所有信息存储在数据库列中。您可以将其余部分存储在 BLOB 列中的序列化对象中。
在表中,有
- 当然有一列表明该行是哪个类的实例
- 一些所有类共有的“核心”列,基本上是基类字段。
- 仅由某些子类使用但我需要搜索的其他列,因此需要对它们进行索引
- 一个包含对象中所有其他数据的 BLOB。
基本上当我在数据库中存储一个对象时,会根据其类填充相关列,并将其余数据(甚至整个对象)推入 BLOB。
这样做的好处是,如果你添加一个不需要搜索或索引,只存储的成员值,你不需要把它放在数据库列中,所以你不需要对数据库:它将存储在序列化的 BLOB 中。唯一要做的就是在你的反序列化代码中为这个成员添加一个默认值,这样已经在数据库中并且没有这个成员的这个类的对象将有一个像样的默认值。
您还可以根据需要对对象格式进行版本控制,它会变得更加复杂。
但是这个方案有一些缺点:
约束很难应用:
- 您只能将约束应用于具有列的字段。
- 由于某些列仅出现在某些类中,因此数据库需要了解您的类层次结构。
例如,您可能希望将地址放在单独的表中,并添加相关字段(邮政编码、国家/地区、街道、号码等):将所有这些都放在主表中会添加太多列。此外,在某些时候,您会想要添加一些客户或其他位于不同表中并且也有地址的东西,因此最好将地址放在单独的表中并引用它们。
对于个人或公司等也是如此。
现在商店有地址,但购物车没有,我想,所以你必须在数据库 DDL 中表示,如果表中的一行是“shop”类型但不是“类型”,则表中的一行必须引用地址购物车”。
它可能会有点毛。
另外,例如,如果您有 10 家商店和 100.000 辆购物车,出于性能考虑,拆分桌子可能会很有趣,这样您就可以得到一张漂亮的快速小桌子和一张大桌子。
现在还有其他解决方案:
例如,您可以将所有代码和基成员放在基类中,但将 tableName 设置为在派生类中更改的类属性。这样,只需更改表名,所有代码都适用于不同的表,而您不必重写任何代码。
然后每个班级有 1 张桌子。
如果您的类层次结构变得更复杂,您当然可以在每个表上应用上述方法。
两者如何选择?
基本上,如果您制作一个网络 CMS 并将其存储在一个表中,则从 Node 派生的类的对象如下:
- 文章
- 带有图例的图像
- 画廊
- 等等
所有这些对象基本上都是相同的东西。
它们都有一个 Title、一个 TextContent 字段、属于一个 ParentNode 等
如果您在 TextContent 中对“foo”进行关键字搜索,如果所有对象都在同一个表中,则会容易得多。
如果您想列出 ParentNode 的所有子节点以将它们显示在网页上,如果所有内容都在 1 个表中,也会容易得多。
所以在这种情况下,第一种方法确实有好处。
现在,在您的情况下,对象并不那么相似。
就我个人而言,我什至不会给他们相同的基类。
我会创建一个名为“ThingWithCoordinates”的 Mixin(可能更短一些)并将其添加到类中。
现在,也许面包店离商店足够近,它可以从商店继承,但推车和货架可能不是。
在你的情况下,我肯定会使用几张桌子。而在每张表中,如果需要存储多个类,我会使用第一种方法。
最重要的是,您的类层次结构(以及表格)必须基于相关的东西(汽车经销商和面包店是商店),而不是碰巧存在于实际上没有其他共同点的对象之间存在的共同特征(如购物车和店铺)。为此,有一些 mixin 可以共享通用代码,但没有基类。