JDO, unowned relationship and persisting multiple objects at once

Go To StackoverFlow.com

0

I would like to have an unowned relationship between two persistence capable classes, created at once. The relationship has to be unowned, because my app can’t really guarantee that the two instances I want to persist will stay in the same entity group for good. My relationship is a bidirectional one-to-many:

// in first class
@Persistent
private Set<Key> instancesOfSecondClass;

// in second class
@Persistent
private Key instanceOfFirstClass;

Then, in one servlet doPost() call, I need to persist one instance per these classes. I actually made a nice methods to maintain both sides of the relationship. First, the Key id (I use …

@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key id;

… as primary keys everywhere) is added to the Set in first class, then a convenience method is called on the instance of second class to notify of this change and update the one Key property accordingly, comparing old values, null checks and everything. Indeed I don’t yet have any Key when the instance is fresh, so I need to persist them both first with pm.makePersistent() call, then do the assignment and wait for pm.close() to happen later.

But, what really happens, is pretty confusing. After running the servlet (whose sole purpose is to return serialized Keys of these two instances for use elsewhere), I go check the datastore viewer and see:

  • the instance of first class got persisted (actually have one more issue here throwing at me NullPointerException from org.datanucleus.store.mapped.mapping.PersistenceCapableMapping.postInsert(PersistenceCapableMapping.java:1039) at the very moment I call pm.makePersistent() on the instance with Set<Key>)
  • the instance of second class got persisted (so far so good)
  • the instance of second class has the Key reference to the first instance persisted, yay
  • the set of Keys on the first instance is… wait for it… empty

The local datastore shows just empty space, while the one online shows <null>, even though my constructor for the class (a one with arguments) creates a new instance of HashSet<T> for the relation.

Using Google App Engine for Java 1.6.4, happened in 1.6.3 too.

Spent a whole day trying to solve this, putting transactions in between, using two PersistenceManagers, different order of persisting calls, cross-group transactions enabling, nothing helped.

Generically, I would be happy to find a working way to create and update two instances in two separate entity groups with unowned relationship between them, no matter of the possible inconsistence (doesn’t worry me that much, based on the frequency of possible updates).

In the mean time, I found two more possible solutions, but haven’t tried them yet: 1. create not only two, but four PersistenceManagers (one to create first instance, second to create second instance, third to update one side of relationship, fourth to update the second side of relationship), or 2. detach the instances and make them persistent again after update. Not sure which way to go now.

2012-04-03 22:34
by themarketka
Or maybe, a third possible solution, the most timely one: upgrade to the bleeding-edge DataNucleus plugin 2.0 - themarketka 2012-04-03 22:40
Seems like I was wrong about the transactions not working, I just used them wrong. Now I put a lot of txn = pm.currentTransaction(); txn.begin(); // the update part txn.commit(); around the updates (create first instance, create second instance, update relationship - due to using cross-group transactions, one transaction is enough for that). Should’ve found that earlier. Anyway, the fact that App Engine didn’t report any kind of concurrency problem worries me and stuck me for a whole day on an actually simple problem. If it only threw some exception or something - themarketka 2012-04-03 23:02
And the v2 of the plugin provides "real" unowned relations rather than hvaing to put a Key and Set of Key in ther - DataNucleus 2012-04-04 06:39
I’ve seen that, but no more info about it in the App Engine’s documentation. But I guess it still needs the same transactions scheme for the required action? Or can I create two new instances, make the relationship, and then persist them - themarketka 2012-04-04 09:01


1

v2 of the plugin provides "real" unowned relations with none of this Key hackery needed before. You can persist both sides in the same transaction if you have the multiple-Entity-Groups flag set, or you can persist them non-transactional.

Just look at the tests for ideas http://code.google.com/p/datanucleus-appengine/source/browse/trunk/tests/com/google/appengine/datanucleus/jdo/JDOUnownedOneToManyTest.java

I have no control over what goes in their docs, just what goes in their code ;-)

2012-04-04 09:13
by DataNucleus
Thanks :-) Is the v2 plugin reliable enough for simple use like this already, so that I can update the code to use it for production? I think I saw in the docs that many-to-many unowned relationships don’t yet work, but I will need these too - themarketka 2012-04-05 14:50
it passes all GAE tests that they had before, and all tests I've added since, so yes. In their docs they typically have a section further down the page, saying in the v2 plugin some other things are supported now - DataNucleus 2012-04-05 15:15
Ads