openjpa-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Henno Vermeulen <he...@huizemolenaar.nl>
Subject RE: How to add children to disconnected entity?
Date Fri, 28 Sep 2012 08:12:03 GMT
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:jtalbut@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:jtalbut@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


Mime
View raw message