在 JPA 上下文中使用 FK 作为 PK 或使用代理 PK 和 FK 作为 FK 的最佳实践是什么?我看到几次有人说他们必须将 FK 映射为 PK,因为他们有遗留数据库。那么这是否意味着对于新表,如果您可以控制创建它们,最好使用以下结构:
TABLE_1
-------
ID (PK)
...
TABLE_2
-------
ID (PK)
TABLE_1_ID (FK)
代替:
TABLE_2
-------
TABLE_1_ID (PK) and (FK)
在 JPA 上下文中使用 FK 作为 PK 或使用代理 PK 和 FK 作为 FK 的最佳实践是什么?我看到几次有人说他们必须将 FK 映射为 PK,因为他们有遗留数据库。那么这是否意味着对于新表,如果您可以控制创建它们,最好使用以下结构:
TABLE_1
-------
ID (PK)
...
TABLE_2
-------
ID (PK)
TABLE_1_ID (FK)
代替:
TABLE_2
-------
TABLE_1_ID (PK) and (FK)
对于多对一关系,请始终使用您提出的第一个替代方案。
对于某些一对一的关系,可以合并表而不会产生不良影响。
第二种选择真正有用的地方是使用类表继承模型实现超类-子类层次结构,正如 Martin Fowler 所提出的那样。在这种情况下,您希望保持子类表与超类表不同,以减少 NULL 的数量。但关系是一对一的。
通过使子类表中的 PK 和 FK 具有相同的键功能,并通过使 FK 引用超类表中的匹配条目,可以在需要时将专用数据与通用数据连接起来非常容易。这可以称为“穷人的遗产”。
我猜你正在寻找@MapsId
注释。
在这种特殊情况下(1 到 0..1 关系),请考虑将两个表合并为一个。
如果它们被故意拆分(例如,对于“垂直”分区),则更喜欢将同一字段同时作为 PK 和 FK。
仅在可以使其更小1时才考虑添加另一个键,但要平衡这与额外索引2的需要、对集群的潜在敌意3以及对菱形依赖关系建模的需要4。
1 例如 因为TABLE_2.TABLE_1_ID
是字符串,你可以制作TABLE_2.ID
整数。
2 每个新索引都会减慢 INSERT 的速度,并且可以减慢 UPDATE 和 DELETE 的速度,具体取决于它们的 WHERE 子句。此外,任何额外的数据都会给缓存带来额外的压力,使其“更小”。
3 聚簇表中的二级索引需要包含 PK 的副本,并且在定位行时会导致双重查找(首先是索引,然后是 PK)。
4 可能需要在“钻石”的两个“边缘”上使用识别关系,以确保钻石的“底部”引用单个“顶部”。