如何为二维数组做 Hibernate ORM 映射

How to do Hibernate ORM mapping for a 2D Array

我是 ORM 的新手,遇到了以下问题(为此处的讨论进行了简化):

我正在为一场比赛建模,其中有参赛者和纪律。两者都有自己的实体 class。参赛者在每个学科中只参加一次比赛,并获得分数。只要参赛者还没有参加过指定学科的比赛,就没有分数。

数据模型:

一个简单的数据库设计将是一个分数 table,同时带有指向竞争对手 table 和学科 table 的外键。也就是说,我会建立两个一对多关系,加上外键的完整性约束——我不能删除竞争对手或学科,只要有分数引用其中任何一个。

但是如何将此二维数组 (competitors/disciplines) 映射到我的 classes 上?我正在使用 Java 和 Hibernate。 我目前的解决方案是将分数集合放入竞争对手实体 class,对于学科 class 也是如此。这为两个实体 classes 中的每一个创建了一个双向关系,其中包含一个连接 table。这是推荐的映射方式吗?

它确实从每个域的角度映射了关系class,但它遗漏了二维数组结构。我想输出整个数组——例如,在 UI 上——包含竞争对手的行、学科的列以及相应 table 单元格中的分数。从刚刚描述的实体 classes 构建这样的输出是乏味的,并且需要 (a) 遍历竞争对手集合,然后 (b) 查找相应的学科 - 或者相反。

理想情况下,我希望有一个带有两个键的散列映射,例如 Guava Table,或者一个嵌套的散列映射。我想这种高级集合没有本地 Hibernate 映射。但也许有一个最佳实践如何使用自定义查询来实现它?

But how do I map this 2D Array (competitors/disciplines) onto my classes? I am using Java and Hibernate. My current solution is to put a collection of scores into the Competitor entity class, and similarly for the Disciplines class. This creates a bidirectional relationship with a join table for each of the two entity classes. Is this the recommended way to do the mapping?

IIRC,隐式连接 table 不允许添加分数。即使是这样,我也不喜欢它,因为分数实际上是主要信息。所以我会去一个明确的 table.

class Score {
    @ManyToOne(optional=false)
    Competitor competitor;
    @ManyToOne(optional=false)
    Discipline discipline;
}

这应该可以提供您需要的一切。您可能还需要 Set<Score> 甚至 Map<Discipline, Score> 在 class Competitor 中(反之亦然,在另一个 class 中),但您可能不需要它。映射可能会使用 @ManyToMany(mappedBy="competitor")@MapKey...我已经很久没有使用它了,因为我发现我真的不需要它。

Ideally, I would like to have a hash map with two keys, like the Guava Table, or a nested hash map.

使用默认设置 @ManyToOne(fetch=EAGER),需要的竞争对手和学科会使用 JOIN 自动获取。恐怕,一个 List 是你所能得到的,但是迭代一次并填充一个 Guava Table 是微不足道的:

list.stream()
.forEach(score -> table.put(score.competitor, score.discipline, score));

只是不要忘记实体是 mutable 但在用作键时不得发生变化。显然,你应该只获取你需要的实体而不是过滤 Table。然而,一旦你拥有了Table,你就可以随意使用它的所有操作; Hibernate 不会再在这里帮助你,但你不需要它(而且你不想再次访问数据库)。