I am writing a wizard to setup a fairly complex object model. The desired behavior is to load values into the wizard out of the database using JPA, edit them through various text fields and combo boxes, and write them back only if the user clicks "Finish" at the end. If the user clicks "Cancel," I want the contents of the database to remain as they were.
The approach I have in mind is:
EntityManager em1; // From the Factory
EntityTransaction tx1 = em1.getTransaction();
tx1.begin();
List<?> docs = em1.createQuery("select d from DocumentRoot d").getResultList();
DocumentRoot doc = (DocumentRoot)docs.get(0);
tx1.commit();
em1.close(); // Now DocumentRoot and all associated objects are detached
if (DocumentEditor.showEditDialog(doc) == APPROVE) { // Mutates doc up the wazoo
EntityManager em2; // From the Factory
EntityTransaction tx2 = em2.getTransaction();
tx2.begin();
em2.merge(doc);
tx2.commit();
em2.close();
}
There is probably some balance of annotations that make this work, but I haven't stumbled upon it. I added cascade = CascadeType.ALL
on all my one-to-many etc. associations, which fixed the "object references an unsaved transient instance
" errors, but now I have "Multiple representations of the same entity [...] are being merged.
"
I have some inkling that the object in question is multiply-represented because there's a many-to-many representation. There's another thread out there suggesting removing CascadeType.MERGE from references to that object, but this seems like a dangerously leaky bandaid. Unsurprisingly, removing that CascadeType.MERGE meant that new entities of the type were not persisted on merge.
It seems like this whole approach -- detach, edit, merge if accepted -- is making JPA very unhappy. Is there another approach that is considered more idiomatic for cases where you want to edit what is effectively a local copy without persisting, and only persisting when the user clicks "OK?"