Hello,
I am using Hibernate 3.2.0 (same result with 3.2.1) on postgres 8.1. I have three classes A,B,C like this: B has some C children and A has some B children. I need the position, so I use lists:
Code:
public class A {
public int id;
public List<B> b = new ArrayList<B>();
public A() { }
public void add(B b) { this.b.add(b); b.a = this; }
}
public class B {
public int id;
public List<C> c = new ArrayList<C>();
public A a;
B() { }
public B(A a) { this.a = a; }
public void add(C c) { this.c.add(c); c.b = this; }
}
public class C {
public int id;
public B b;
public C(B b) { this.b = b; }
}
The mapping file is:
Code:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="fr">
<class name="A" table="A">
<id access="field" name="id" type="int" column="A_ID" length="4">
<generator class="sequence"><param name="sequence">a_id_seq</param></generator>
</id>
<list access="field" name="b" lazy="true" inverse="false">
<key column="A_ID" not-null="true" unique="true" />
<index column="B_IDX" />
<one-to-many class="B" />
</list>
</class>
<class name="B" table="B">
<id access="field" name="id" type="int" column="B_ID" length="4">
<generator class="sequence"><param name="sequence">b_id_seq</param></generator>
</id>
<list access="field" name="c" lazy="true" inverse="false">
<key column="B_ID" not-null="true" unique="true" />
<index column="C_IDX" />
<one-to-many class="C" />
</list>
<many-to-one access="field" name="a" class="A"
foreign-key="FK_B_A" column="A_ID" insert="false" update="false"
not-null="true" />
</class>
<class name="C" table="C">
<id access="field" name="id" type="int" column="C_ID" length="4">
<generator class="sequence"><param name="sequence">c_id_seq</param></generator>
</id>
<many-to-one access="field" name="b" class="B"
foreign-key="FK_C_B" column="B_ID" insert="false" update="false"
not-null="true" />
</class>
</hibernate-mapping>
I create a very small hierarchy:
Code:
a-b1-c
|-b2
public static void test() {
A a = new A();
B b1 = new B(a);
B b2 = new B(a);
C c = new C(b1);
Transaction tx = null;
try {
Session session = getSession();
tx = session.beginTransaction();
session.save(a);
tx.commit();
session.evict(a);
// [...]
tx = session.beginTransaction();
A a1 = b1.a;
session.refresh(a1);
a.add(b1);
session.save(b1);
tx.commit();
session.evict(a1);
session.evict(b1);
// [...]
tx = session.beginTransaction();
A a2 = b2.a;
session.refresh(a2);
a.add(b2);
session.save(b2);
tx.commit();
session.evict(a2);
session.evict(b2);
// [...]
tx = session.beginTransaction();
B b = c.b;
session.refresh(b);
b.add(c);
session.save(c);
tx.commit();
session.evict(b);
session.evict(c);
} catch (HibernateException e) {
e.printStackTrace();
}
}
The database access code has 4 sections separated with [...]. They are actually 4 DAO operations. Notice the explicit eviction. I get the following exception at the line session.save(c):
Code:
org.hibernate.PropertyValueException: not-null property references a null or transient value: fr.C._cBackref
at org.hibernate.engine.Nullability.checkNullability(Nullability.java:72)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:284)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:180)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.saveWithGeneratedOrRequestedId(DefaultSaveOrUpdateEventListener.java:186)
at org.hibernate.event.def.DefaultSaveEventListener.saveWithGeneratedOrRequestedId(DefaultSaveEventListener.java:33)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsTransient(DefaultSaveOrUpdateEventListener.java:175)
at org.hibernate.event.def.DefaultSaveEventListener.performSaveOrUpdate(DefaultSaveEventListener.java:27)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.java:70)
at org.hibernate.impl.SessionImpl.fireSave(SessionImpl.java:535)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:523)
at org.hibernate.impl.SessionImpl.save(SessionImpl.java:519)
at fr.cs.interdistance.persistence.dao.ADAO.test(ADAO.java:56)
at fr.cs.interdistance.persistence.helpers.SchemaExport.test(SchemaExport.java:71)
at fr.cs.interdistance.persistence.helpers.SchemaExport.main(SchemaExport.java:36)
However, if I change
Code:
C c = new C(b1);
into
Code:
C c = new C(b2);
it works. Also, removing the explicit evictions solves the problem. Anyone knows why?
Thanks