0

I have the following scenario:

class A {
 @OneToMany(mappedBy = "a", cascade = {CascadeType.PERSIST})
 List<B> bsOfA;
 @OneToMany(mappedBy = "a", cascade = {CascadeType.PERSIST}) 
 List<C> csOfA;
}

class B {
 @OneToMany(mappedBy = "b", cascade = {CascadeType.PERSIST})
 List<D> dsOfB;
 @ManyToOne
 A a;
}

class C {
 @OneToMany(mappedBy = "c", cascade = {CascadeType.PERSIST})
 List<D> dsOfC;
 @ManyToOne
 A a;
}

class D {
 @ManyToOne
 C c;
 @ManyToOne
 B b;
 @ManyToOne
 A a;
}

Then, I am attempting to save A along with all its associated entities as follows:

a = new A(aId);
b = new B(bId);
c = new C(cId);
d = new D(dId);
a.setBsOfA(List.of(b));
a.setCsOfA(List.of(c));
b.setDsOfB(List.of(d));
c.setDsOfC(List.of(d));
repo.save(a)

Now my problem is, I am getting a foreign key violation because the order of insertion is incorrect. Checking my logs, I am seeing the following order of insertion: a -> b -> d (error c not yet existing)

How can I enforce Hibernate to insert in the correct order: a -> b -> c -> d OR a -> c -> b -> d

10
  • My first inclination would be to suggest refactoring your persistence schema to avoid the kind of cycles that you show. I have no idea whether that's actually plausible for you, though, the entities presented being so abstract. Commented Sep 22 at 16:12
  • There shouldn't be a cycle. This might not be the best analogy but... A has 2 sets of children birthed from different partners: set B and set C. Now for some reasons, a member of b and a member of c births an incestuous offspring D... Commented Sep 22 at 16:20
  • 1
    You aren't showing exactly how you set D's reference to A, B, and Cs - are they set? If they aren't, no JPA provider can tell at the object level that D is dependent on A B or C being inserted first. What happens if you Save D and cascade from that side instead? You could persist/save A, B, C, Ds independently before setting the relationships if you need more control - but I know this works in other JPA providers like EclipseLink, so I'm sure there is something overlooked here too. Commented Sep 22 at 16:43
  • Actually, I am not setting them. I am only setting the OneToMany relationships since I assumed that those are where the cascade persists relationships depend on. Commented Sep 22 at 16:48
  • There is definitely a cycle, by which I mean in the graph theory sense: A->B->D->C->A. This is why you observe the problem you describe. I find such a schema pretty questionable, and I'm inclined to think that most real-world schemas having such a feature could be refactored to remove it. If yours is not such a schema, or if refactoring is impractical, then you're probably going to need to live with less cascading. Commented Sep 22 at 17:00

1 Answer 1

0

For anyone who might be encountering the same problem as me, the answer is to make sure all references are assigned correctly. Both forward and back. Also, I was initially wondering why a particular foreign key is causing problems while others are not. It turns out this particular foreign key is NOT NULLABLE while the others are so it didn't cause a problem. Initially, I was not setting the back references, I only set the references sufficient to perform cascade persist. Example, in the case above, I linked D to B so that when B is saved, D will also be saved. BUT, I did not link D to C so JPA had no idea that D is dependent on both B and C. Also, I removed the reference from C to D because in my case I didn't really need the relationship to be bidirectional.

Sign up to request clarification or add additional context in comments.

2 Comments

I don't believe you needed to modify the object model - this wasn't a cycle. A cycle if when each table has a foreign key to another such as if A->B->C->A. OneToMany and M:M are not included in cycle dependencies as they are not holding FKs themselves. In your model D->C->A, D->B->A, and D->A. There is no cycle back from A to B, C or D.
You're right. I did not make the modification because of there is no cycle in the directed graph. I just realized that I didn't really need it to be bidirectional so I removed it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.