Problem persisting without cascade [message #1369851] |
Tue, 20 May 2014 19:28 |
Randy Tidd Messages: 8 Registered: August 2013 |
Junior Member |
|
|
We are using EclipseLink 2.4.2. We have a data model (simplifying) A ->> B <<- C <<- D. Up until recently we had CascadeType.MERGE and CascadeType.PERSIST defined on all of these relationships, so that merging or persisting would cascade to the other entities.
We have experienced what we think are problems with the cascade behavior especially when merging a combination of attached and detached objects. This is a topic for another posting... but suffice it to say we are experimenting with turning off the cascading on all relationships and essentially managing the cascade behavior ourselves.
So in the entity classes we have cascade merge and persist turned off. To persist these objects they must be saved in the database in reverse order i.e. D, C, B, A. So we have, essentially:
A a = new A();
B b = new B();
C c = new C();
D d = new D();
a.addB(b);
b.setA(a);
b.setC(c);
c.addB(b);
c.setD(d);
d.addC(c);
em.persist(d);
em.persist(c);
em.persist(b);
em.persist(a);
However, on the first call to persist() we get this error:
During synchronization a new object was found through a relationship that was not marked cascade PERSIST: ...
followed by a string representation of "c". Essentially when we try to persist the instance of "d", EclipseLink is traversing all of D's data mappings, finding the object "c" which we haven't persisted yet (because we can't because they have to be persisted in order), and throwing the error.
The upshot is that with "cascade persist" turned off, we can't build the object graph and then persist it as we need to.
I understand that something like this might work:
D d = new D();
em.persist(d);
C c = new C();
c.setD(d);
d.addC(c);
em.persist(c);
B b = new B();
b.setC(c);
c.addB(b);
em.persist(b);
A a = new A();
a.addB(b);
b.setA(a);
em.persist(a);
However, our use case is that we need to build up the full object graph ahead of time; the full data model has over 100 entities and a typical graph has between 250 and 500 objects and assembling this object graph is very complex. Persisting the objects at every step along the way would introduce dependencies between our domain objects and database that we can't support and also complicate our transaction management since we need to roll back the entire transaction if any operation fails.
So I want to make sure I'm understanding this problem correctly and to see if there are any other solutions that I haven't considered. Thanks in advance for any information.
Randy
|
|
|
|
Re: Problem persisting without cascade [message #1371910 is a reply to message #1371719] |
Wed, 21 May 2014 15:44 |
Randy Tidd Messages: 8 Registered: August 2013 |
Junior Member |
|
|
Thanks for the reply Chris.
The error occurs either when a call to EntityManager.flush() is made, or when the transaction scope closes, for example when a method marked @TransactionAttribute(TransactionAttributeType.REQUIRED) finishes. The behavior is the same in both cases leading me to believe that changing the transaction behavior won't have any effect.
Taken at face value the error seems straightforward, just like the error message says, it is traversing all relationships and finding objects that have not been persisted, which is a failure condition. The fact that this leads to a failure is what surprises us.
In our architecture we have tried to separate the creation and editing of our domain classes (which are JPA classes) and the persisting / merging of them. Imagine for example a batch job that receives a 20MB XML file, and we have a job that creates an object graph of 250-500 objects to represent that data, then we need to save that all at once. That logic is complex and spread through various parts of the architecture and transformations. If we are required to persist each new object when it was created and before it was associated to any others, then all of that logic would have to be bound to an Entity Manager and JPA would be a dependency throughout the architecture.
Instead we are trying to build the object graph and then send it to what is essentially a saving service, which will then persist or merge everything. With cascading enabled this works most of the time, but we need to get this working without JPA-configured cascading, if possible.
Randy
|
|
|
Re: Problem persisting without cascade [message #1372074 is a reply to message #1371910] |
Wed, 21 May 2014 17:18 |
Chris Delahunt Messages: 1389 Registered: July 2009 |
Senior Member |
|
|
Sorry, I'm not sure I was clear. You mentioned the error was happening on the em.persist(d); call, and now are saying the error occurs on the flush. The point I was trying to make is that flush or transaction commits cannot occur until the state of the managed model is valid. That means all objects in D's object graph need to be persisted before a flush can occur without error. D cannot reference a non-persisted C when a flush occurs or the transaction is committed, as D isn't referencing a managed entity until C is persisted. C and its referenced new entities must also be persisted in the same transaction context.
You will need to do one of the following:
a) manually persist references in the object model in the same transactional context.
b) re-enable the cascade persist on relationships that make sense with your usage patterns.
c) set relationships after persisting objects. Such as using a factory for creation that gives back a persisted object
Best Regards,
Chris
[Updated on: Wed, 21 May 2014 17:19] Report message to a moderator
|
|
|
Powered by
FUDForum. Page generated in 0.03978 seconds