Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Eclipse Projects » EclipseLink » Problem persisting without cascade
Problem persisting without cascade [message #1369851] Tue, 20 May 2014 19:28 Go to next message
Randy Tidd is currently offline Randy TiddFriend
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 #1371719 is a reply to message #1369851] Wed, 21 May 2014 14:09 Go to previous messageGo to next message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1089
Registered: July 2009
Senior Member
Hello Randy,

The error states that the EntityManager is synchronizing to the database - essentially flushing or committing. This should not occur if the persist calls are done within the same EntityManager and transaction. How is the EM and transaction being managed?

If this isn't a configuration issue, you will need to persist your entities and then set the relationships. One way to do that would be to create a factory to instantiate new instances up front and persist them at the same time in an extended persistence unit, then let your code set relationships and start, join and commit a transaction later. See http://en.wikibooks.org/wiki/Java_Persistence/Transactions#Join_Transaction
Re: Problem persisting without cascade [message #1371910 is a reply to message #1371719] Wed, 21 May 2014 15:44 Go to previous messageGo to next message
Randy Tidd is currently offline Randy TiddFriend
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 Go to previous message
Chris Delahunt is currently offline Chris DelahuntFriend
Messages: 1089
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

Previous Topic:Prepersist ISSUE with merge(when creating a new entity).
Next Topic:Problem adding more entity classes
Goto Forum:
  


Current Time: Fri Sep 04 21:02:46 GMT 2015

Powered by FUDForum. Page generated in 0.02370 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software