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

我有两个表:

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


我也有一个联接表:

TSJoin
tsjoin_id, employee_id


TimeSheet只有一名员工。因此,对于任何给定的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()但这很丑陋。

最佳答案

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

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

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


  referencedColumnName
  
  (可选)此外键列引用的列的名称。 [...]
  
  缺省值(仅在使用单个连接列的情况下适用):与引用表的主键列同名。


所以你所需要的就是

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


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

07-28 11:55