Hibernate 3.6: how to use pending FK constraints when inserting objects with a circular reference?

Consider the following Hibernate 3.6 entity mapping with a circular reference in objects A and B:

@MappedSuperclass abstract class Entity { @Id protected UUID id = UUID.randomUUID(); @Version protected Integer revision; } @Entity class A extends Entity { // not null in the database @OneToOne(optional = false) B b; } @Entity class B extends Entity { // not null in the database @ManyToOne(optional = false) A a; } 

An entity identifier is generated when a new instance is created, so it is set before any SQL INSERT. To determine if an instance is temporary or not using an Interceptor :

 class EntityInterceptor extends EmptyInterceptor { @Override public boolean isTransient(Object entity) { return ((Entity)entity).getRevision == null; } } 

When I try to save (in one transaction) instances of A and B (with links set to each other), Hibernate fails with a TransientObjectException error (the object refers to an unsaved transient instance - it saves a temporary instance before flushing).

 A a = new A(); B b = new B(); a.setB(b); b.setA(a); // start transaction sessionFactory.getCurrentSession().saveOrUpdate(a); // a before b or vice versa doesn't matter sessionFactory.getCurrentSession().saveOrUpdate(b); sessionFactory.getCurrentSession().flush(); // commit 

When I change the mapping to cascading Ab and Ba Hibernate generates the following SQL INSERT statement for A:

 INSERT INTO A (id, revision, b) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, NULL); 

This violates the NOT NULL on Ab and raises a ConstraintViolationException . Although identifier B is known at insert time, it is not set to SQL INSERT. In the database (PostgreSQL 9.1), the FK restriction on Ab is defined by DEFERRABLE INITIALLY DEFERRED , so if Ab is set, the following INSERT statements will be executed without any errors:

 START TRANSACTION; INSERT INTO A (id, revision, b) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb'); INSERT INTO B (id, revision, a) VALUES ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 0, 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'); COMMIT; 

When I remove the NOT NULL constraint on Ab in the database and save the cascading save mapping, this code to save A and B works fine. EDIT The NOT NULL cannot be delayed in PostgreSQL, only the FK constraint can be delayed. END EDIT Honestly, I did not consider the generated SQL statements in this case (and I cannot reproduce it right now), but I assume that it looks like this:

 START TRANSACTION; INSERT INTO A (id, revision, b) VALUES ('aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa', 0, NULL); INSERT INTO B (id, revision, a) VALUES ('bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb', 0, 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'); UPDATE A SET b = 'bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb' WHERE id = 'aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa'; COMMIT; 

I know that there may be a better entity design for what I am trying to do here in the first place, but I would really like to know if there is a way to preserve the NOT NULL (and, if possible, also the original mapping without cascading saving) and make my source code work. Is there a way to tell Hibernate to just insert A with Ab = B.id, although B is temporary during insert A? As a rule, I could not find any documentation regarding Hibernate and pending FK restrictions, so any pointers to this were appreciated.

+4
source share
1 answer

Here you have the classic bi-directional connection . both sides have a link to each other. If you have bidirectonal, one side should be marked as the stronger side, this is done using ussing mappedBy or vice versa to mark the wick. In addition, you have FK limitations, so you need to determine that not-null is true so that sleep mode is inserted with FK.

look at .

+1
source

All Articles