Java JDO-更新一对一子级

Java JDO-更新一对一子级,java,google-app-engine,jdo,Java,Google App Engine,Jdo,我有一个食谱。每个食谱都有一个图像。所以我的实体看起来像 @PersistenceCapable public class Recipe { @PrimaryKey @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY) private Key key; @Persistent private MyImage myImage; 当我第一次创建菜谱时,效果非常好,图像非常清晰 也添加了,我可以查看它。但是当

我有一个食谱。每个食谱都有一个图像。所以我的实体看起来像

@PersistenceCapable
public class Recipe {
   @PrimaryKey
   @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
   private Key key;
   @Persistent
   private MyImage myImage;
当我第一次创建菜谱时,效果非常好,图像非常清晰 也添加了,我可以查看它。但是当我去更新它的时候 作为

新图像被添加到数据存储中,但是当我尝试获取它时 在配方中,配方仍然指向我的 数据存储。这正常吗?我怎样才能解决这个问题

这是我的jdoconfig.xml文件的内容

<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>



我想你应该打电话给
pm.makePersistent(r)

无需执行
pm.makePersistent(r)因为配方已经是持久的。
但在代码示例中,您使用非事务性读取,这意味着您可以从数据存储中读取实例,而无需事务。
但是,如果要进行持久性修改,则需要使用事务

   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();
   }

我认为JDO的AppEngine实现以父键的形式存储所拥有的关系。当您将myImageA设置为recipe1的子级时,appengine会将MyImage实体的父级设置为recipe1

我不是这方面的专家,但我猜当您将myImageB设置为recipe1的子对象时,appengine只是将另一个MyImage实体的父对象设置为recipe1。当它去检索
myImage
时,它会查找父级为
recipe1
的图像,并且仍然会找到
myImageA
,即使
myImageB
仍在那里

再说一遍,我猜。我希望有一个“提交猜测”选项

TL;DR:在设置
myImageB
之前,我会尝试显式删除
myImageA
。这将打破对myImageA的所有其他引用,但如果您希望从其他上下文中使用它,那么拥有的关系无论如何都是不合适的


这种令人困惑的混乱正是我放弃JDO&完全拥有关系并学会爱客观化的原因。它们还限制了实体组的选项,这增加了雾的另一个维度。

对我来说,有效的方法是获取需要更新的旧对象,然后更改对象,然后存储它。调整您的代码将为我们提供:

   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();
   }

这基本上就是我所做的,而且似乎有效

你能发布你的
jdoconfig.xml
的内容吗。您是否更改了该文件中的任何内容,特别是
datanucleus.appengine.autoCreateDatastoreTxns
?我还尝试了事务。同样的结果。图像添加到数据存储中,但配方对象仍然指向第一个图像。如果执行pm.refresh(r),会发生什么情况?在
tx.commit()之前添加该图像。同样的结果:(我认为您不必使用事务来持久化对对象的更改。猜测:AppEngine只需在关闭pm时对您更改的对象调用
put
。您是否发现了这一点?我也遇到了同样的问题。希望赏金会有所帮助。@Lumpy,不幸的是,我完全放弃了所有关系,以支持of无主关系。我在网上找不到任何帮助,这里的声誉也帮不上忙。是的,不幸的是,我还放弃了app engine的JDO。这是一个标准层,使我的app engine应用程序在google世界之外工作。objectify在google Store之外工作吗?不,objectify是100%特定于app engine的:(这正是我最终所走的道路。如果您没有创建新对象,而是获取该对象,更新它,然后存储它,这似乎是可行的。在已经持久化的对象上调用makePersistent应该是不必要的;关闭PersistenceManager应该可以保存更改。
   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();
   }