I guess I can answer my own question: just use CascadeType.MERGE anyway.

The workaround I suggested can get very complex for a bit more complex entity 
graphs because you may then need to keep track of multiple properties of 
multiple entities before and after saving and write their new value and you 
have to know which entity before merge corresponds to which after which isn't 
trivial because new objects don't have (auto generated) id's yet. 

JPA cascade already has the ability to correctly do what I want, so simply 
marking the relation Contact.department as CascadeType.MERGE (/PERSIST 
depending on how you persist) solves the problem. JPA will not insert multiple 
Departments but correctly make the references to the same saved Department.

The only possible problem I get is that I may accidentally set a reference to a 
new Department outside of the Customer entity graph. If this is a real problem 
it is possible to add custom code to guard against this.

Henno


-----Oorspronkelijk bericht-----
Van: Henno Vermeulen [mailto:he...@huizemolenaar.nl] 
Verzonden: dinsdag 16 juli 2013 11:56
Aan: 'users@openjpa.apache.org'
Onderwerp: persisting a new structure with two references to a new object

I have three unpersisted entities, let's call them Customer, Department and 
Contact.

-          Customer refers to Department using CascadeType.ALL

-          Customer refers to Contact using CascadeType.ALL

-          Contact refers to (the same) Department using no cascade

I wish to save all three new objects by persisting the new Customer; this 
situation must also be supported in my UI.
When I do this (through entityManager.merge) I get this error:

new object in persistent field "Contact.department" during attach.  However, 
this field does not allow cascade attach. Set the cascade attribute for this 
field to CascadeType.MERGE or CascadeType.ALL (JPA annotations) or "merge" or 
"all" (JPA orm.xml). You cannot attach a reference to a new object without 
cascading.

I explicitly do NOT want to cascade persist/merge the Contact.department 
relation because Department must always be persisted through Customer.  
Contact.department is a simple (nullable) reference that may later be changed 
to refer to another Department.

Of course it is logical that I get this error when Contact.department refers to 
a new Department when it is not in the object graph that I am persisting. But 
in this case the new Department will be cascade persisted through Customer so 
it's new primary key could in principle be used for the foreign key 
Contact.department. So I was hoping that somehow OpenJPA was smart enough to do 
this.

One possible way I can think of to implement this logical "save" operation is 
by explicitly checking if the Department is new and if so merging it in two 
steps: first merge the Customer graph by setting Contact.department = null, 
then "manually" setting it to the newly saved Customer.department and merge 
again.
Unfortunately this is extra code for the same logical "save" operation. Is 
there some way to tell OpenJPA to merge without throwing this exception or 
should I simply use such a workaround?

Henno

Reply via email to