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:
org.datanucleus.store.mapped.mapping.PersistenceCapableMapping.postInsert(PersistenceCapableMapping.java:1039)at the very moment I call
pm.makePersistent()on the instance with
Keyreference to the first instance persisted, yay
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.
txn = pm.currentTransaction();
// 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.
I have no control over what goes in their docs, just what goes in their code ;-)