伙计们,
连续第n次,我再次遇到同样的老问题.它是关于"如何以无痛的方式将OOP结构映射到数据库表".
这是一个场景:我的系统中有几种类型的"演员" - 工人,雇主,联系人.它们具有某些共同的功能; 其他作品则截然不同.所有参与者处理的实体都是"通信","笔记"(管理员喜欢给客户留言)等等.每种演员类型处理的其他实体有很多类型,而其他实体则没有.
目前,我的数据库架构包括以下表:
演员:
工人
雇主
联系
实体:
通讯
笔记
等等
实体和参与者之间的关联表:
工人通信ASSN
雇主通信ASSN
工人笔记,ASSN
等等,你得到了演练.
这对我来说就像一个"代码味道".每当客户改变他们的角色(即从"联系人"提升为"雇主")时,就需要运行一堆疯狂的脚本.哎呀...另一方面,如果我在纯粹的OOP驱动的世界中运行,这将更容易 - 为具有共同属性的所有实体提供基类,并完成它...
在DB世界中,这个选项似乎在理论上是可行的,但听起来非常混乱......即如果我理解这一点,我会有一个新的base_actor表,而其他每个actor都会有一个base_actor_id,然后关联将介于两者之间base_actor和实体......但是,我如何进行反向关联查询?即"向我展示与工人类型的演员的所有沟通"?
有什么建议?关于"将OOP结构映射到关系数据库"主题的一般想法?
..这是关于"如何以无痛的方式将OOP结构映射到数据库表".
你没有.
面向对象和关系代数是两种根本不同的范例.没有主观解释,你不能在它们之间转换.这被称为阻抗不匹配,被称为计算机科学越南.
它被称为ORM或对象关系映射.有许多产品旨在帮助您将OO结构映射到关系表.例如,Ruby on Rails提供Active Record以帮助弥合鸿沟.对于PHP,您有Propel和Doctrine以及Porte和许多其他人.
这是我10年前提出的解决方案.使用此设计的系统仍在运行,因此它的运行时间比我的大多数代码都要长.;)今天我可以使用Scott提到的一个ORM包,但是直接使用SQL确实没有大问题.
将所有继承关系建模为表之间的连接.系统中的每个表都将包含特定类的属性.
使用合成对象id(oid)作为所有对象的主键.序列生成器或自动增量列是生成oid值所必需的.
所有继承的类必须使用与其父类相同的oid类型.将oid定义为具有级联删除的外键.父表获取自动增量oid列,子项获取普通的oid列.
最终类的查询在相应的表上进行.您可以将所有父类表连接到查询中,也可以延迟加载所需的属性.如果您的继承层次结构很深并且您有许多类,那么ORM包可以真正简化您的代码.我的系统少于50个类,最大继承深度为3.
跨子类的查询(即父类的查询)可以基于每个实例延迟加载子属性,也可以对与基类连接的每个子类重复查询.基于父类查询的延迟加载子属性要求您知道对象的类型.您可能已经在父类中有足够的信息,但如果没有,则需要添加类型信息.同样,这是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;
最后一件事.确保您拥有良好的数据库和正确的索引.如果数据库无法优化这些连接,则性能可能是一个严重的问题.