一尘不染

关系数据库中类似面向对象的结构

mysql

民间,

我连续第n次遇到相同的老问题。这是关于“如何轻松地将OOP结构映射到数据库表”。

这是一个场景:系统中有几种类型的“角色”-工人,雇主,联系人。它们具有某些共同的功能。其他部分则大不相同。所有参与者所处理的实体是“交流”,“注释”(管理员喜欢在客户身上留下注释)等。每种角色类型都处理大量其他类型的实体,而其他类型则不。

当前,我的数据库模式包括以下表:

演员:

  • 工人
  • 雇主
  • 联系

实体:

  • 通讯
  • 笔记
  • 等等

实体和参与者之间的关联表:

  • 工人交流协会
  • 雇主交流协会
  • 工人笔记
  • 等等,您就可以开始练习了。

对我来说,这感觉像是一种“代码气味”。每当客户更改其角色时(即从“联系人”升级为“雇主”),都需要运行大量疯狂的脚本。uck
…另一方面,如果我在一个纯粹的OOP驱动的世界中工作,这会容易得多-为具有公共属性的所有实体都拥有一个基类,并以此为基础…

在数据库世界中,该选项在理论上似乎是可行的,但是听起来很混乱……也就是说,如果我理解这一权利,我将拥有一个新的base_actor表,并且每个actor都将具有base_actor_id,然后关联将在base_actor和实体…但是,如何执行反向关联查询?即“向我展示与类型工作者的所有交流”吗?

有什么建议吗?关于“将OOP结构映射到关系数据库”有什么一般想法?


阅读 236

收藏
2020-05-17

共1个答案

一尘不染

这是我大约十年前提出的解决方案。使用该设计的系统仍在运行,因此与我的大多数代码相比,它可以很好地生存。;)今天,我可能会使用Scott提到的ORM软件包之一,但是直接使用SQL确实没有大问题。

  1. 将所有继承关系建模为表之间的联接。系统中的每个表都将包含特定类的属性。

  2. 使用合成对象ID(oid)作为所有对象的主键。序列生成器或自动增量列对于生成oid值是必需的。

  3. 所有继承的类必须使用与其父类相同的oid类型。使用级联删除将oid定义为外键。父表获取自动增量oid列,子表获取普通oid列。

  4. 有关最终类的查询在相应的表上进行。您可以将所有父类表加入查询中,也可以延迟加载所需的属性。如果您的继承层次结构很深并且您有很多类,那么ORM包可以真正简化您的代码。我的系统有少于50个类,最大继承深度为3。

  5. 跨子类的查询(即,对父类的查询)可以按实例延迟加载子属性,也可以对与基类连接的每个子类重复查询。根据父类查询延迟加载子属性需要您知道对象的类型。父类中可能已经有足够的信息,但是如果没有,则需要添加类型信息。同样,这是ORM软件包可以提供帮助的地方。

没有成员属性的虚拟类可以在表结构中跳过,但是您将无法基于这些类进行查询。

这就是“向我展示与类型工作者的所有交流”的样子。

select * from comm c, worker w where c.actor=w.oid;

如果您有通信的子类,并且要立即加载所有子类属性(也许您的系统不允许部分构造),则最简单的解决方案是急于加入所有可能的类。

select * from comm c, worker w, missive m where c.actor=w.oid and c.oid=m.oid;
select * from comm c, worker w, shoutout s where c.actor=w.oid and c.oid=s.oid;

最后一件事。确保您具有良好的数据库和正确的索引。如果您的数据库无法优化这些联接,则性能可能是一个严重的问题。

2020-05-17