在休眠 ORM 中使用一个强制外键和一个可选外键中的列

Posted

技术标签:

【中文标题】在休眠 ORM 中使用一个强制外键和一个可选外键中的列【英文标题】:Using a column in one mandatory and one optional foreign key in hibernate ORM 【发布时间】:2021-10-21 09:05:45 【问题描述】:

我想在一个实体内的一个可选和一个强制复合外键中使用一个字段。

我有三个不同的实体,TeamPersonShard。人员属于一个团队 ManyToOne。两个实体都有一个ShardID,它是Shard 的外键。

所有团队和人员的 ID 仅在每个分片中唯一,但它们也只会引用具有相同分片 ID 的其他实体。他们的 ShardID 是他们主键的一部分。

Shard
---
PK       ID
UNIQUE   Name
Team
---
PK, FK1   ShardID
PK        ID
---
FK1 (ShardID -> Shard)
Person
---
PK, FK1, FK2   ShardID
PK             ID
FK2            TeamID
---
FK1 (ShardID -> Shard)
FK2 (ShardID, TeamID -> Team)

此外,Person -> Team 关系是可选的。 Person 可能不是 Team 的成员,这可能会随着时间而改变。

在尝试在 JPA 中为 Person 对象建模时,我遇到了一个问题。显然,当我将ShardID 建模为主键的一部分和作为外键列时,休眠给了我Repeated column in mapping for entity 错误。我可以使用insertable = false, updatable = false 来防止这种情况发生:

    // This contains the shard_id column
    @EmbeddedId
    protected PersonId id;
    
    @ManyToOne(optional = true)
    @JoinColumns(
        @JoinColumn(name = "shard_id", insertable = false, updatable = false), 
        @JoinColumn(name = "team_id", nullable = true)
    )

但我不能这样做,因为休眠要求所有JoinColumnsinsertableupdatable 具有相同的设置,并且我需要能够在以后向该人添加一个团队。 ShardID 将始终存在,但 TeamID 可能不存在。

如何在休眠 JPA ORM 中实现这一点?我浏览了 O/R 建模的休眠文档,但找不到方法。我一直在研究表继承,但这感觉很不自然,并不能解决“可选问题”。

这个例子不包含我的实际数据模型,只是一个简化的例子。

【问题讨论】:

【参考方案1】:

你可以尝试像这样使用@JoinColumnOrFormula

@JoinColumnOrFormulas(
    @JoinColumnOrFormula(formula = @JoinFormula(value = "shard_id", referencedColumnName = "shard_id")), 
    @JoinColumnOrFormula(column = @JoinColumn(name = "team_id", referencedColumnName = "id", nullable = true))
)

【讨论】:

这个解决方案是特定于 Hibernate 的,对吗?我找不到 Hibernate 的 JoinFormula 的实现,它采用“名称”属性并且不需要 value 属性,所以我尝试使用 shard_id 作为 value。我还必须在JoinColumn 上指定referencedColumnName = "id"。这不会在数据库中创建外键关系,但如果结构已经存在,我可以使用该对象。 是的,这是 Hibernate 特有的,因为 JPA 不支持这一点。我纠正了错别字。

以上是关于在休眠 ORM 中使用一个强制外键和一个可选外键中的列的主要内容,如果未能解决你的问题,请参考以下文章

休眠仅保存具有复合主键中的父外键的子表条目

Django中ORM外键和表的关系(Django编程-4)

完整性约束语法定义

完整性约束语法定义

在 DataGridView 中过滤外键

SQL中怎么向外键中插入数据