Reputation: 1298
Using Hibernate 5 as ORM.
I use to think that optional=true
meant that the column could hold null values.
I have two entities -:
An Elective may or may not be associated with an ElectivePractical but an ElectivePractical must always be associated with an Elective.
Elective.java
public class Elective extends Theory {
private static final long serialVersionUID = 1L;
@Column (name = "ELEC_NO",
table = "ELECTIVES",
length = 3)
private String electiveNo;
@OneToOne (targetEntity = ElectivePractical.class,
mappedBy = "elective",
fetch = FetchType.EAGER,
cascade = CascadeType.ALL,
optional = true)
private ElectivePractical practical;
@ManyToMany(targetEntity = Student.class,
fetch = FetchType.EAGER,
mappedBy = "electives")
private Collection<Student> students = new ArrayList<>();
ElectivePractical.java
public class ElectivePractical extends Practical {
private static final long serialVersionUID = 1L;
@OneToOne (targetEntity = Elective.class,
fetch = FetchType.EAGER,
cascade = CascadeType.MERGE)
@JoinTable (name = "ELECTIVE_PRACTICAL",
joinColumns = @JoinColumn (name = "ELEC_PRAC_ID",
referencedColumnName = "ID", nullable = false),
inverseJoinColumns =
@JoinColumn (name = "ELEC_THEORY_ID",
referencedColumnName = "ID", nullable = false))
private Elective elective;
As you can see that ElectivePractical
in Elective.java
is set to optional=true
Yet when I try to merge()
an Elective instance that has no practical I get the following error -:
javax.persistence.PersistenceException: org.hibernate.PropertyValueException: not-null property references a null or transient value : com.sts.entity.subjects.Elective.practical
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1692)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1602)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1608)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1171)
at com.sts.persistence.STSDao.addCourse(STSDao.java:250)
at com.sts.validators.CourseValidator.commit(CourseValidator.java:558)
at test.main.CourseTest.main(CourseTest.java:27)
Caused by: org.hibernate.PropertyValueException: not-null property references a null or transient value : com.sts.entity.subjects.Elective.practical
at org.hibernate.engine.internal.Nullability.checkNullability(Nullability.java:92)
at org.hibernate.action.internal.AbstractEntityInsertAction.nullifyTransientReferencesIfNotAlready(AbstractEntityInsertAction.java:115)
at org.hibernate.action.internal.AbstractEntityInsertAction.makeEntityManaged(AbstractEntityInsertAction.java:124)
at org.hibernate.engine.spi.ActionQueue.addResolvedEntityInsertAction(ActionQueue.java:185)
at org.hibernate.engine.spi.ActionQueue.addInsertAction(ActionQueue.java:163)
at org.hibernate.engine.spi.ActionQueue.addAction(ActionQueue.java:150)
at org.hibernate.event.internal.AbstractSaveEventListener.addInsertAction(AbstractSaveEventListener.java:325)
at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:272)
at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:178)
at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.jpa.event.internal.core.JpaMergeEventListener.saveWithGeneratedId(JpaMergeEventListener.java:56)
at org.hibernate.event.internal.DefaultMergeEventListener.saveTransientEntity(DefaultMergeEventListener.java:255)
at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:235)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:173)
at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:69)
at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:839)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:821)
at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:826)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:1161)
... 3 more
What am I doing wrong ? Is this a bug in hibernate ?
Upvotes: 0
Views: 2352
Reputation: 12225
The optional=true
element is only used for generation of the DDL, as well as validation of the schema. If you have created the database manually, the actual database column might well be NOT NULL
even if your Hibernate-mapping says the opposite.
By the way, your mappings can be slimmed down, for instance I don't think you need targetEntity
with newer versions of Hibernate.
Update:
I see you are using mappedBy
on the same side as the optional=true
-element. The mappedBy
-element tells Hibernate
that the other side of the relationship contains the actual mapping. It might be that this includes the optional=true
-element, so that it is ignored. Try adding it to the other side of the relationship.
Upvotes: 2