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 Key
s of these two instances for use elsewhere), I go check the datastore viewer and see:
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>
)Key
reference to the first instance persisted, yayThe 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 PersistenceManager
s, 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 PersistenceManager
s (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.
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
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 ;-)