JDO - Updating a One-to-one child
I have a Recipe. Each Recipe has an image. So my entity looks something like
@PersistenceCapable
public class Recipe {
@PrimaryKey
@Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
private Key key;
@Persistent
private MyImage myImage;
When I create the Recipe the first time, it works great, the image is added as well and I can view it. However when I go and update it such as
PersistenceManager pm = PMF.get().getPersistenceManager();
Recipe r = pm.getObjectById(Recipe.class, recKey);
try {
r.setImage(newImage);
} finally {
pm.close();
}
the new image is added to the data-store, but when I try and fetch it from within the recipe, the recipe still points to the old image in my data-store. Is this normal? How can I fix this?
Here is the co开发者_开发问答ntent of my jdoconfig.xml file
<jdoconfig xmlns="http://java.sun.com/xml/ns/jdo/jdoconfig"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="http://java.sun.com/xml/ns/jdo/jdoconfig">
<persistence-manager-factory name="transactions-optional">
<property name="javax.jdo.PersistenceManagerFactoryClass"
value="org.datanucleus.store.appengine.jdo.DatastoreJDOPersistenceManagerFactory"/>
<property name="javax.jdo.option.ConnectionURL" value="appengine"/>
<property name="javax.jdo.option.NontransactionalRead" value="true"/>
<property name="javax.jdo.option.NontransactionalWrite" value="true"/>
<property name="javax.jdo.option.RetainValues" value="true"/>
<property name="datanucleus.appengine.autoCreateDatastoreTxns" value="true"/>
</persistence-manager-factory>
</jdoconfig>
I think the AppEngine implementation of JDO stores owned relationships in the form of parent keys. When you make myImageA a child of recipe1, appengine sets the parent of a MyImage entity to recipe1.
I'm not an expert on this, but I'm guessing that when you make myImageB a child of recipe1, appengine just sets the parent of another MyImage entity to recipe1. When it goes to retrieve myImage
, it looks for an image with a parent of recipe1
, and still finds myImageA
, even though myImageB
is still sitting there.
Again, I'm guessing. I wish there was a "Submit Guess" option.
TL;DR: I'd try deleting myImageA
explicitly before setting myImageB
. That would break every other reference to myImageA
, but if you're hoping to use it from other contexts an owned relationship is inappropriate anyway.
This kind of confusing mixup is why I dropped JDO & owned relationships altogether and learned to love Objectify. They also constrain your options for entity groups, which adds another dimension of fog.
I think you got to call pm.makePersistent(r);
after setting the new image object to actually persist your change.
It is not required to do pm.makePersistent(r);
because the Recipe is already persistent.
But in your code example you use non transactional read which means you can read instances from the datastore without a Transaction.
But if you want to do persistent modifications you need to use a Transaction.
PersistenceManager pm = PMF.get().getPersistenceManager();
Transaction txn = pm.currentTransaction();
txn.begin();
Recipe r = pm.getObjectById(Recipe.class, recKey);
try {
r.setImage(newImage);
txn.commit();
} finally {
pm.close();
}
What worked for me was getting the old object that needed to be updated then changing the object then storing it. Adjusting your code gives us:
PersistenceManager pm = PMF.get().getPersistenceManager();
Recipe r = pm.getObjectById(Recipe.class, recKey);
MyImage newImage = r.getMyImage();
newImage.setImage(newImageFile);
try {
r.setImage(newImage);
pm.makePersistent(r);
} finally {
pm.close();
}
This is basically what I did and it seems to work.
精彩评论