为什么我通过 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 中使用非主键列。我们的遗留数据库连接到不是主键的列。
我搜索过,但似乎找不到答案。
我有两个 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 中使用非主键列。我们的遗留数据库连接到不是主键的列。