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

时间:2015-08-31 18:00:45

标签: java hibernate jpa hibernate-mapping

我已经搜索过,但似乎无法找到答案。

我有两张桌子:

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

我还有一个联接表:

TSJoin
tsjoin_id, employee_id

TimeSheet只有一个Employee。因此,对于任何给定的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)

为Employee返回null。

它使用TimeSheet的主键并尝试匹配连接表的主键。

我做错了什么?

修改

我还想声明我此时只设置了一个方向。哪个是TimeSheet -> Employee(OneToOne),而Employee未映射到TimeSheet 尚未。不确定这是否有所不同,但我想提一下。

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

2 个答案:

答案 0 :(得分:1)

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

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

所以你需要告诉Hibernate。它无法猜测。 javadoc of JoinColumn说:

  

referencedColumnName

     

(可选)此外键列引用的列的名称。 [...]

     

默认值(仅在使用单个连接列时适用):与引用表的主键列相同的名称。

所以你需要的只是

ts_id

请注意,每个时间表只有一名员工并不足以使您的关联成为OneToOne。要成为OneToOne,每位员工也应该有一张时间表。事实上,如果一个emplyee有几个时间表,那么关联就是ManyToOne,而不是OneToOne。

答案 1 :(得分:1)

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