Reputation: 47
I have a class B which has a set with objects of class A. Objects from class A can reference each other. So i am loading object from class B which has already one object from class A added. Now i am adding a new object from class A, which will be referenced by the first. When i try to save this, most of the time it will end in an EntityNotFoundException. I could try saving from last item to first, but this will not work if you see this example:
public class A implements java.io.Serializable {
private BigInteger id;
private A succes;
private A fail;
public A(BigInteger id) {
this.id = id;
}
public void setSuccess(A a) {
this.success = a;
}
public void setFail(A a) {
this.fail = a;
}
}
public class B implements java.io.Serializable {
private Set<A> setA = new HashSet<A>();
public void addA(A a) {
this.setA.add(a);
}
public Set<A> getSetA() {
return this.setA;
}
}
public class Util {
public static void update(B b) throws JDBCException, PSQLException {
EntityManager em = null;
EntityTransaction tx = null;
try {
em = HibernateUtil.getEntityManagerFactory().createEntityManager();
tx = em.getTransaction();
tx.begin();
em.merge(b);
tx.commit();
} catch (Exception e) {
tx.rollback();
logger.error(e);
e.printStackTrace();
Throwable cause = e.getCause();
if (cause instanceof JDBCException) {
throw (JDBCException) cause;
}
if (cause instanceof PSQLException) {
throw (PSQLException) cause;
}
} finally {
em.close();
}
}
public static BigInteger getNextID() {
// returns next value of sequence
}
}
public static void main(String[] args) {
B b = ... // load from DB
A a1 = b.getSetA.get(0);
A a2 = new A(Util.getNextID());
A a3 = new A(Util.getNextID());
A a4 = new A(Util.getNextID());
a1.setSuccess(a2);
a2.setSuccess(a3);
a3.setSuccess(a4);
a4.setFail(a2);
b.addA(a2);
b.addA(a3);
b.addA(a4);
Util.update(b); // throws javax.persistence.EntityNotFoundException Unable to find A with id xxx
}
From the XML-HBM-file of class B:
<set embed-xml="true" fetch="select" cascade="all-delete-orphan"
lazy="true" mutable="true" name="A"
optimistic-lock="true" table="A" inverse="true"
sort="unsorted">
<key>
<column name="A_ID" />
</key>
<one-to-many
class="A" embed-xml="true"
not-found="exception" />
</set>
How should i solve this?
Edit: I can use
em.unwrap(Session.class).update("B", b);
But this ends in an IllegalArgumentException: Removing a detached instance when removing an object from class A.
Upvotes: 4
Views: 800
Reputation: 6435
With the additional information given in the comments, we found that the solution is to persist the A
instances manually before adding them to an instance of B
.
As the ids of A
are manually created in the code before the instances are persisted, hibernate "thinks" that the instances should be available in the database as they have an ID which is not generated by the database. This causes the EntityNotFoundException
when updating a B
before all A
s are persisted.
There are actually two different solutions:
A
either via an IDENTITY
column or by using a SEQUENCE
. With that, hibernate can cascade the persists from B
to A
.A
s before adding them to B
. This is only necessary if the IDs are manually created.And since the requirements in question are that the IDs are available before actually persisting each A
, solution 2 must be used here. In fact, it is even most probably necessary, to persist each A
, before calling either setSuccess(a2)
and setFail(a2)
.
Upvotes: 1