I need to use Hibernate persistence for a Java class with reflexive relationship to itself where the relationship is one-to-one, optional on both sides, recorded in a separate mapping table. I.e:
Code:
@Entity(name = "Clazz")
@Table(name = "clazz")
class Clazz {
private Integer id;
private Clazz foo;
private Clazz bar;
...
@Id
@Column(name="id", ..., nullable=false)
@GeneratedValue(...)
public Integer getId() {return id;}
@OneToOne(mappedBy = "bar")
public Clazz getFoo() {return foo;}
public void setFoo(Clazz foo) {...}
@OneToOne
@JoinTable(
name = "mapping",
joinColumns = @JoinColumn(name = "foo_id", referencedColumnName = "id"),
inverseJoinColumns = @JoinColumn(name = "bar_id", referencedColumnName = "id")
)
public Clazz getBar() {return bar;}
public void setBar(Clazz bar) {...}
...
}
DB:
DESC mapping;
Name Null? Type
------ -------- -------------
foo_id NOT NULL VARCHAR2(256)
bar_id NOT NULL VARCHAR2(256)
DESC clazz;
Name Null? Type
------ -------- -------------
id NOT NULL VARCHAR2(256)
I have existing data populated in the DB and when I try to update one Clazz object as follows:
Clazz c1 = ...; // this object has c1.foo == null
Clazz c2 = ...;
c1.setBar(c2);
c2.setFoo(c1);
...
// Hibernate Session.merge() is called on c1
then I get this exception:
org.hibernate.PropertyValueException: not-null property references a null or transient value: Clazz.foo
I don't understand why a non-null a.foo is required when no such requirement is specified in the Hibernate annotations (OneToOne.optional == true by default). Furthermore, my expectation is that hypothetical setting of a null value there is even valid and should remove a corresponding record from the mapping table.
Could you, please, tell me what I am doing wrong of if this is a bug in Hibernate (v3.x)?