我在尝试使用JPA(提供者:Hibernate)建立一个单向一对一的关系时遇到了很大的困难。我认为这不应该太麻烦,但显然JPA / Hibernate并不同意 ;-)
问题在于,我必须映射一个我无法更改的旧架构,并且此架构在两个实体之间使用共享主键,同时这个主键又是一个实体的外键。
我创建了一个简单的测试案例:
数据库如下:
CREATE TABLE PARENT (PARENT_ID Number primary key, Message varchar2(50));
CREATE TABLE CHILD (CHILD_ID Number primary key, Message varchar2(50),
CONSTRAINT FK_PARENT_ID FOREIGN KEY (CHILD_ID )REFERENCES PARENT (PARENT_ID));
CREATE SEQUENCE SEQ_PK_PARENT START WITH 1 INCREMENT BY 1 ORDER;
父实体(即一对一关系的拥有方)如下所示:
@Entity
@Table(name = "PARENT")
public class Parent implements java.io.Serializable {
private Long parentId;
private String message;
private Child child;
@Id
@Column(name = "PARENT_ID", unique = true, nullable = false, precision = 22, scale = 0)
@SequenceGenerator(name="pk_sequence", sequenceName="SEQ_PK_PARENT")
@GeneratedValue(generator="pk_sequence", strategy=GenerationType.SEQUENCE)
public Long getParentId() {
return this.parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
@Column(name = "MESSAGE", length = 50)
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
@OneToOne (cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn(name="PARENT_ID", referencedColumnName="CHILD_ID")
public Child getTestOneToOneChild() {
return this.child;
}
public void setTestOneToOneChild(Child child) {
this.child = child;
}
}
孩子:
@Entity
@Table(name = "TEST_ONE_TO_ONE_CHILD", schema = "EXTUSER")
public class Child implements java.io.Serializable {
private static final long serialVersionUID = 1L;
private Long childId;
private String message;
public Child() {
}
public Child(String message) {
this.message = message;
}
@Id
@Column(name = "CHILD_ID")
public Long getChildId() {
return this.childId;
}
public void setChildId(Long childId) {
this.childId = childId;
}
@Column(name = "MESSAGE", length = 50)
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
}
我完全理解JPA不知道如何为子对象分配ID的问题。然而,我也尝试使用Hibernate的“foreign”键生成器,但也没有成功,因为这需要从子对象中引用父对象,这是不可取的。
在我看来,这个问题并不太罕见,那么我错过了什么?有解决方案吗?如果纯JPA无法提供解决方案,我也可以使用Hibernate扩展。
我对正确行为的期望是:
- 从序列中获取ID,并将其设置到父对象上
- 持久化父对象
- 将父对象的ID设置到子对象上
- 持久化子对象
如果我尝试持久化一个“独立”的子对象(例如entityManager.persist(aChild)),我希望会抛出RuntimeException异常。
非常感谢任何帮助!