知识卡片
对象与关系表现"连接"方式的根本差异,是阻抗不匹配的核心
内容
对象-关系映射真正棘手的地方在于对象和关系模型处理”连接”的方式根本不同,这体现在两点:其一,表现方式不同——对象通过运行时的引用(内存地址)来表示连接,关系数据库通过指向另一张表的键值来表示连接;其二,多值处理能力不同——对象可以轻松用集合表示”一对多”引用,但关系规范化要求所有关系连接都必须是单值的,这导致对象和表之间的数据结构方向是颠倒的:一个订单对象自然拥有一个订单项集合、订单项无需持有订单引用,但表结构里订单项必须持有指向订单的外键,因为订单表不能有多值列。解决表现问题的通用思路是:给每个对象一个标识域来承载它的关系身份,用标识映射做关系键与对象之间的相互查找。在此基础上,针对不同的连接形态各自有专门的模式来处理:单值域和一对多集合域用外键映射(结合延迟加载避免不必要的查询);多对多关联(两边都是集合)用关联表映射,额外建一张纯关系表来承接;只在拥有者范围内使用、不对外暴露的从属对象用依赖映射简化;日期范围、货币这类没有独立身份的小型值对象用嵌入值直接摊平进宿主对象的表;相对独立、高度互连的一整串小对象(如层次化的组织结构图)则可以用序列化LOB整体存成一个大字段,用一次读取换取避免大量小型数据库调用的开销,代价是SQL无法感知这个大字段内部的结构、难以对其做可移植查询。
结构图:
flowchart TB
A["对象-关系阻抗不匹配"]
A --> B["表现方式不同<br/>对象:内存引用 vs 关系:外键"]
A --> C["多值能力不同<br/>对象:集合 vs 关系:规范化单值"]
B --> D["单值/一对多引用 → 外键映射"]
C --> E["多对多 → 关联表映射"]
D --> F["从属对象不对外用 → 依赖映射简化"]
D --> G["无独立身份的小值对象 → 嵌入值"]
D --> H["高度互连的小对象群 → 序列化LOB"]
参考来源
- 位置:《企业应用架构模式》第一部分"表述"之"第3章 映射到关系数据库"之"3.4 结构映射模式"(源文件:_epub-src/OEBPS/Text/000020.html)
- 结论依据:原文说明"这里的关键问题在于对象和关系处理连接的方法不同……对象是通过在运行时(内存管理环境或内存地址)中保存引用的方式来处理连接的。关系数据库则通过创建到另外一个表的键值来处理连接……对象可以很容易通过集合来表示多个引用,而规范化则要求所有的关系连接都必须是单值的。这就导致对象和表之间的数据结构颠倒了",并分别给出外键映射/关联表映射/依赖映射/嵌入值/序列化LOB各自的适用场景,直接支撑本卡结构图。
- 原始内容:一个订单对象自然拥有一个订单项的集合,而这些订单项不需要持有订单对象的引用。然而,表结构中的各订单项必须包含一个到订单的外键,因为订单不能有一个多值域。