I'm trying to map a bi-directional lazy OneToOne relationship using a JoinTable to avoid having Hibernate eagerly load the related object [see
http://www.hibernate.org/162.html,
http://opensource.atlassian.com/projects/hibernate/browse/HHH-3653].
The use of the JoinTable does avoid the eager load of the related object, however an exception is generated during the persisting of the object graph when the OneToOne mapping with the JoinTable is mapped with cascade=Cascade.ALL. If the cascade is not specified, the persisting of the object graph works correctly.
Shouldn't the cascade work in this situation?
Hibernate version:
Hibernate Core 3.3.1.GA
Hibernate Annotations 3.4.0 GA
Hibernate EntityManager 3.4.0 GA
Schema:
Code:
create table PERSON (
PERSON_ID NUMBER(21) PRIMARY KEY
);
create table STUDENT (
STUDENT_ID NUMBER(21) PRIMARY KEY
);
create table PERSON_STUDENT (
PERSON_ID NUMBER(21) NOT NULL REFERENCES PERSON(PERSON_ID),
STUDENT_ID NUMBER(21) NOT NULL REFERENCES STUDENT(STUDENT_ID),
PRIMARY KEY (PERSON_ID, STUDENT_ID)
);
Annotated Classes:Code:
// Annotated Person Entity
@Entity
@Table(name="PERSON")
public class Person {
@Id
@GeneratedValue
@Column(name="PERSON_ID")
private Long id;
@OneToOne(optional=true,
fetch=FetchType.LAZY,
cascade = CascadeType.ALL // Removing the cascade will allow the persist to work
)
@JoinTable(name = "PERSON_STUDENT",
joinColumns = @JoinColumn(name="PERSON_ID"),
inverseJoinColumns = @JoinColumn(name="STUDENT_ID")
)
private Student student;
public Long getId() {
return id;
}
public Student getStudent() {
return student;
}
public void setStudent(Student student) {
this.student = student;
}
}
Code:
// Annotated Student Entity
@Entity
@Table(name="STUDENT")
public class Student {
@Id
@GeneratedValue
@Column(name="STUDENT_ID")
private Long id;
@OneToOne(mappedBy="student",
optional=false,
fetch=FetchType.LAZY
)
private Person person;
public Long getId() {
return id;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
Persist Test:Code:
public class OneToOnePersistTest {
public static void main(String[] args) throws Exception {
EntityManagerFactory emf = null;
EntityManager em = null;
try {
emf = Persistence.createEntityManagerFactory("onetoonetest");
em = emf.createEntityManager();
em.getTransaction().begin();
Person person = new Person();
Student student = new Student();
person.setStudent(student);
student.setPerson(person);
em.persist(person);
//em.persist(student); // need this if cascade is not specified
em.getTransaction().commit();
}
catch (Exception e) {
if (em != null && em.getTransaction().isActive())
em.getTransaction().rollback();
throw e;
}
finally {
if (em != null) em.close();
if (emf != null) emf.close();
}
}
}
Stack Trace of Exception:Code:
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value: entities.Student.person
at org.hibernate.ejb.AbstractEntityManagerImpl.throwPersistenceException(AbstractEntityManagerImpl.java:614)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:226)
at test.OneToOnePersistTest.main(OneToOnePersistTest.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value: entities.Student.person
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:95)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:313)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:636)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:628)
at org.hibernate.engine.EJB3CascadingAction$1.cascade(EJB3CascadingAction.java:28)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.java:291)
at org.hibernate.engine.Cascade.cascadeAssociation(Cascade.java:239)
at org.hibernate.engine.Cascade.cascadeProperty(Cascade.java:192)
at org.hibernate.engine.Cascade.cascade(Cascade.java:153)
at org.hibernate.event.def.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:454)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:288)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:204)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:144)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:49)
at org.hibernate.event.def.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110)
at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61)
at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:645)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:619)
at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:623)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:220)
... 6 more
Generated SQL:Code:
Hibernate:
select
hibernate_sequence.nextval
from
dual
Hibernate:
select
hibernate_sequence.nextval
from
dual
Database:
Oracle 10g