为什么我通过 JoinTable 进行的 OneToOne 映射不起作用?

Why does my OneToOne mapping through a JoinTable not work?

我搜索过,但似乎找不到答案。

我有两个 table:

select ts_id, tsjoin_id, workdate from TimeSheets
select e_id, lastname from Employees

我也有加入table:

TSJoin
tsjoin_id, employee_id

一张时间表只有一名员工。因此,对于任何给定的 TimeSheet 实体,我希望能够:

TimeSheet ts = tsService.getTimeSheet(123);
String lastName = ts.getEmployee().getLastName();

在 SQL 中,获取 TimeSheet 的员工:

select e.lastname from TimeSheets t
    join TSJoin x on (x.tsjoin_id = t.tsjoin_id)
    join Employees e on (e.e_id = x.employee_id)
where t.ts_id = 123

在我的 Hibernate 映射中,我有:

@OneToOne
@JoinTable(
        name = "TSJoin",
        joinColumns = {
                @JoinColumn(name = "tsjoin_id", nullable = false)
        },
        inverseJoinColumns = {
                @JoinColumn(name = "e_id", nullable = false)
        }
)

但是,它生成的 SQL 是:

select * from TimeSheet t
    left outer join TSJoin x on (t.ts_id = x.tsjoin_id)

其中 returns 员工为 null。

它正在获取 TimeSheet 的主键并尝试匹配连接的主键 table。

我做错了什么?

编辑

我还想声明一下,我目前只设置了一个方向。这是一个 TimeSheet -> Employee (OneToOne) 并且 Employee 尚未映射到 TimeSheet 。不确定这是否有影响,但我想提一下。

编辑 2 我还想声明,我认为错误可能是因为我的联接 table 不包含对 TimeSheet 的引用。 Hibernate 假设连接 table 将包含所涉及的每个实体(遗留数据库)的主键。我可能会创建 TimeSheet -> JoinTable -> Employee 的映射并将其访问为: ts.getJoin().getEmployee() 但这很丑陋。

默认情况下,假定连接 table 包含两个连接实体的 ID。

在您的情况下,它没有:TimeSheet 实体的 ID 映射到 ts_id 列,但您希望连接 table 有一个外键列到 tsjoin_id 列而不是 ts_id.

因此您需要将其告知 Hibernate。它猜不出来。 javadoc of JoinColumn 表示:

referencedColumnName

(Optional) The name of the column referenced by this foreign key column. [...]

Default (only applies if single join column is being used): The same name as the primary key column of the referenced table.

所以你只需要

@JoinTable(
    name = "TSJoin",
    joinColumns = {
            @JoinColumn(name = "tsjoin_id", nullable = false, referencedColumnName = "tsjoin_id")
    },
    inverseJoinColumns = {
            @JoinColumn(name = "e_id", nullable = false)
    }
)

请注意,每个时间表有一名员工不足以使您的关联成为 OneToOne。要成为 OneToOne,每个员工还应该有一个时间表。如果一个员工实际上有多个时间表,则关联是 ManyToOne,而不是 OneToOne。

我几乎 100% 肯定这个问题是因为当前的 JPA 规范不允许在 JoinTable 中使用非主键列。我们的遗留数据库连接到不是主键的列。