Nice to see that my (too?) elaborate story has helped you. Indeed a UUID should 
solve this problem. (I considered this myself but did not use one because it 
shifts the responsibility of assigning the id to the client and I wasn't really 
sure if this is a good idea.)

Normally I would simply merge/persist C and let OpenJPA handle merging A by 
cascading but I guess you are still left with the problem that B references C 
as well and depending on the model B may not be cascaded.

-----Oorspronkelijk bericht-----
Van: Jim Talbut [mailto:jtal...@spudsoft.co.uk] 
Verzonden: donderdag 27 september 2012 22:12
Aan: users@openjpa.apache.org
Onderwerp: Re: How to add children to disconnected entity?

Thanks for that.

What I was doing was to persist C and then merge A, which resulted in C 
becoming C', when I then persisted B OpenJPA could find no connection 
between C and C'.
The C entities only get an ID when they are persisted.
I was hoping that C' would retain knowledge of C, which would let my 
scenario work, but it doesn't seem to.

My fix was to add a UUID to C and store that in B instead of C itself.
If I was starting again I would have made the UUID the ID, but the 
database already exists and changing the PK is too much at this stage.

Jim

On 27/09/2012 09:27, Henno Vermeulen wrote:
> Hi,
>
> Not sure I exactly understand the situation. Perhaps you are using cascade 
> merge on both of the objects that refer to it?
> Normally you shouldn't use cascade merge when it is only an association and 
> use cascade merge when the entity really "owns" the other entity.
>
> Suppose A and B both refer to C (A -> C, B -> C) and C is owned by A.
> Then the relation A -> C should use cascade merge but B -> C should not.
> If C is an existing entity and you merge A, C will be merged as well. If you 
> then merge B which refers to the same C, this should succeed even if the 
> version of C contained in B is an old one. The relation B -> C does not use 
> cascade merge so when merging B only the identity of C matters. (If it would 
> cascade merge you would get an optimistic lock exception if you use that or 
> otherwise you could overwrite C with old data).
>
> Perhaps you are in the situation where you are using id generated by OpenJPA 
> and C is not yet persisted. I always regard two objects that are not 
> persistent but have exactly the same data to be different from each other. 
> The reason is that the act of merging does not change the parameter to merge. 
> Instead it returns an attached object which represents the same logical 
> entity in the database but does not refer to the same object in memory. I 
> always regard merge as a save operation that does not change the parameter so 
> I throw away the entity passed-in and work with the retuned one. I always 
> take care to first merge an unpersisted entity before I use it in an 
> associaton with another entity.
>
> Detailed explanation of what happens: when B refers to a "clone" of the 
> unpersisted C there is absolutely no way for OpenJPA to recognize that B has 
> a reference to the same C as A has. Suppose you start out with an A and B 
> referring to the same unpersisted C in memory. You then merge A and this 
> cascade merges C. The result of the merge operation will contain a now 
> persistent copy of C but the original unpersisted C object in memory is not 
> changed, i.e. the C that results from the merge refers to another object in 
> memory. If you then merge B you should get an exception that the relation 
> does not allow cascade because B still refers to the unpersisted C. However 
> if the relation B -> C was set to cascade merge, then you will end up with B 
> referring to another new instance that has the same data as C but does not 
> have the same database identity.
>
> Hope this explanation helps, even though it may not be your exact situation. 
> The moral of the story that I learned over time is to realize that merge does 
> not alter its parameter so that you should really regard two unpersisted 
> clones as different. And it's usually better to use cascade merge only on one 
> relation, i.e. from it's owner to the entity. This will prevent the bugs that 
> you can silently get a duplicate or merge an older version.
>
> -----Oorspronkelijk bericht-----
> Van: Jim Talbut [mailto:jtal...@spudsoft.co.uk]
> Verzonden: woensdag 26 september 2012 23:05
> Aan: users@openjpa.apache.org
> Onderwerp: Re: How to add children to disconnected entity?
>
> On 26/09/2012 10:57, Jim Talbut wrote:
>> On 26/09/2012 10:19, Henno Vermeulen wrote:
>>> Hi,
>>>
>>> I verified this situation by making an extra unit test in our system.
>>> We always work with detached entities as well. The test works fine
>>> for me.
>>>
>>> One explanation for this behavior is that the @OneToMany field does
>>> not use "fetch = FetchType.EAGER" because relations are lazily
>>> fetched by default. (Or alternatively you have not included the field
>>> in OpenJPA's FetchPlan before calling entityManager.merge which has
>>> the same effect as FetchType.EAGER even if the @OneToMany field is
>>> not eager).
>>>
>>> When I adjust my test to lazily fetch the field, then saving a new
>>> Assessment somehow DOES cascade merge new AssessmentResults. However
>>> when I merge an existing Assessment that has one existing
>>> AssessmentResult and one new AssessmentResult, OpenJPA will not
>>> cascade merge it.
>>>
>> Thank you.
>> Yes, that is precisely what I'm going to be doing.
>> The results are large, so they are Lazy loaded, and the assessments
>> are created in a different transaction - so the list is always empty
>> when first loaded.
>>
>> What I'm doing at the moment is, in the function that calls merge,
>> iterating through the results and persisting any that aren't contained
>> or detached.
>> I have to do that first (before merging the assessment) or some
>> results get persisted twice.
>> This seems to be working (well, one of my unit tests passed, I've got
>> other unit tests failing and that may not be related to this).
>>
>> Jim
> I've got that nearly all working now, but I've still got one big problem.
>
> The detached entity that I create has two objects referring to it: one
> of which gets merged and the other gets persisted.
> The act of merging attaches the new entity, but replaces the variable
> the refers to it.
> So when the other entity gets persisted I end up with a duplicate entity.
>
> This is all caused by trying to break down big transactions into much
> smaller ones, which is why it's not the best structure.
>
> Jim

Reply via email to