jplams / datanucleus-appengine

Automatically exported from code.google.com/p/datanucleus-appengine
0 stars 0 forks source link

Entity relationship, owned or unowned, is always dependent #290

Closed GoogleCodeExporter closed 8 years ago

GoogleCodeExporter commented 8 years ago
I use current latest GAE SDK (version 1.7.0) and for accessing the datastore I 
use JDO 3.0 and DataNucleus Plugin (everything provided by the SDK, nothing 
external). The exact versions are: DataNucleus Plugin 2.0.1, DataNucleus API 
JDO 3.0.7, DataNucleus Core 3.0.10, JDO API  3.1 SNAPSHOT 20110926.

According to the documentation, an owned relationship can be "dependent" but in 
my case, the relationship is always dependent, meaning that child objects are 
always deleted with parent object. I tried to use @Element(dependent = 
"false"), but it had no effect. 

The same problem applies to unowned relationships. They are always dependent. 
There is a little difference though.

When removing an object from the collection by calling .remove( ), the object 
is always deleted from the datastore for both owned and unowned relationship. 
However when I call .clear() on the collection, for unowned relationships, the 
objects are kept in the datastore. For owned relationships they are deleted.

I tried to deploy the application but the behavior is the same when running on 
Google servers.

The definitions of entities which I've been experimenting on are attached. 

Steps to reproduce the problem:

1. Create entity A

pm.makePersistent(new A("some string"));

2. Add some objects to an unowned relationship (Long id contains the id of the 
previously added A entity).

A a = pm.getObjectById(A.class, id);
B x = new B("bx");
B y = new B("by");
B z = new B("bz");
pm.makePersistent(x);
pm.makePersistent(y);
pm.makePersistent(z);
a.getB().add(x);
a.getB().add(y);
a.getB().add(z);
pm.makePersistent(a);

3. Destroy the relationship between the A entity and its first child.

A a = pm.getObjectById(A.class, id);
a.getB().remove(0);
pm.makePersistent(a);

At this point, only the reference between entities should be removed. But 
instead the original B entity is permanently deleted from the datastore as 
well. No matter whether the relationship is defined as owned or unowned, 
dependent or not dependent. The only difference is when using clear() as 
described above:

A a = pm.getObjectById(A.class, id);
a.getB().clear();
pm.makePersistent(a);

For owned relationships, this deletes all B entities in the relationship, for 
unowned, it doesn't.

I attached also jdoconfig.xml in case it mattered. I use Spring MVC in my 
project.

Original issue reported on code.google.com by tobiaspo...@gmail.com on 14 Aug 2012 at 5:41

Attachments:

GoogleCodeExporter commented 8 years ago
Three updates:

1) I switched back to DataNucleus plugin v1 and JDO 2, but the behavior 
described above is still the same.

2) When caching a parent entity, all its descendants also get cached. According 
to the documentation, child objects are fetched from the datastore when 
accessed for the first time. I don't know it, but I guess it could be possible 
that the serialization process could trigger the lazy loading. I don't know how 
to properly test if the child objects are fetched before even the caching 
starts, but if they really are, and at least appstats statistics suggest that 
they are, the problem is most likely related to this one, described above. It 
seems to me, that in my case JDO with datanuclues plugin are like "hungry 
animals". They don't ask, they don't care, they just fetch/delete as much as 
possible. 

3) To be really really sure that this isn't just a problem of my application, I 
created a new one, completely empty. I simply followed the official 
documentation, got JDO working and then tested the code above. The result was 
the same.

Please could anyone look into it? Or is this ok, meaning it works as it should, 
just the documentation is old? But how do I delete the parent entity without 
deleting the child object? Or fetch parent object without fetching the whole 
entity group? 

Original comment by tobiaspo...@gmail.com on 18 Aug 2012 at 11:42

GoogleCodeExporter commented 8 years ago
So it seems, that #2 is really related to the cache. I run some tests and it  
seems that without caching the child objects are not fetched, lazy loading 
works as it should. However the original problem remains.

Original comment by tobiaspo...@gmail.com on 19 Aug 2012 at 8:10

GoogleCodeExporter commented 8 years ago
As per the docs, owned relations are always dependent (since they have an 
owner, and if not related to the owner then they make little sense).
Unowned relations was incomplete in that it didn't process the 
dependent-element setting and just fell back to the behaviour for owned 
relations; SVN trunk fixes that.

Original comment by googleco...@yahoo.co.uk on 19 Aug 2012 at 9:48

GoogleCodeExporter commented 8 years ago
Thanks, that's relieving. It would be great, if someone could update GAE 
documentation, which clearly claims that it _can_ be dependent. It's confusing.

Original comment by tobiaspo...@gmail.com on 19 Aug 2012 at 9:52

GoogleCodeExporter commented 8 years ago
Hello there,

I still face this issue actually.

App Engine 1.8.4
Datanucleus plugin 2.1.2
Datanucleus JDO 3.1.3
Classes are enhanced using version 3.1.1 of the enhancer

Class A have unowned list of class B

1. Persist Bx
2. Persist By
3. Persist Bz
4. Persist Ax
5. Persist Ay
6. Ax.addAll([Bx,By,Bz])
7. Ay.addAll([Bx,By,Bz])
8. remove let's say By from Ax list

Result: By is entirely removed even from Ay list

Tried to force (dependent = "false") but still the same and marked the list 
with @Unowned even though is not in the one-to-many example: 
https://developers.google.com/appengine/docs/java/datastore/jdo/relationships#Un
owned_Relationships

Any intel?

Should I build using Ant as stated in the doc 
https://developers.google.com/appengine/docs/java/datastore/jdo/overview-dn2#Set
ting_Up_JDO_3_0 or is it, as I suspect, outdated as almost every single Google 
documention? (Datanucleus v2 can now be selected in the project properties for 
ages)

Thanks for any help or explanation,
Charles

Original comment by char...@guide2com.fr on 20 Sep 2013 at 9:37

GoogleCodeExporter commented 8 years ago
As I've struggled with this for ages, let me share the solution that finaly 
works for me. Who knows, it might help someone else as the documentations are 
not very helpful.

To remove a child from the parent's collection without deleting the original 
persitent object you need to:

1) Use a Set not a List

At first I used only Lists, A) for the ordering and B) because Sets + 
RequestFactory ValueProxy doesn't work. So be sure to use EntityProxy

2) Anotate this set with @Unowned

This annotation is not in the Unowned one-to-many example: 
https://developers.google.com/appengine/docs/java/datastore/jdo/relationships#Un
owned_Relationships
But without it you get an exception when you try to add an element to your set 
(can't change parent)

3) Not sure it's necessary but I've also annotated with @Element(dependent = 
"false")

Hope this will help some people. If not, well, no harm done.

Original comment by char...@guide2com.fr on 22 Oct 2013 at 2:36