Мне очень тяжело пытаться получить однонаправленное отношение "один к одному" для работы с JPA (Provider: Hibernate). По-моему, это не должно быть слишком много хлопот, но, по-видимому, JPA/Hibernate не согласны с этим; -)
Проблема в том, что мне нужно сопоставить устаревшую схему, которую я не могу изменить, и что эта схема использует общий первичный ключ между двумя объектами, который одновременно является внешним ключом для одного объекта.
Я создал простую TestCase:
DB выглядит следующим образом:
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 для ребенка. Однако я также пробовал использовать "чужой" генератор ключей Hibernates, также безуспешно, потому что нужно иметь обратную ссылку на родителя от ребенка, что нежелательно. Эта проблема не кажется мне слишком необычной, так что мне здесь не хватает? Есть ли решение? Я также могу использовать расширения для спящего режима, если чистая JPA не предоставляет решение.
Мои ожидания относительно правильного поведения: Если я попытаюсь сохранить родителя с прикрепленным дочерним элементом:
- получить идентификатор из последовательности, установить его на родительский
- persist parent
- установить родительский идентификатор для дочернего
- упорный ребенок
Если я попытаюсь сохранить "автономный" дочерний элемент (например, entityManager.persist(aChild)), я бы ожидал исключение RuntimeException.
Любая помощь очень ценится!