【问题标题】:JDO - Updating a One-to-one childJDO - 更新一对一的孩子
【发布时间】:2011-04-07 13:50:13
【问题描述】:

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

@PersistenceCapable
public class Recipe {
   @PrimaryKey
   @Persistent(valueStrategy = IdGeneratorStrategy.IDENTITY)
   private Key key;
   @Persistent
   private MyImage myImage;

当我第一次创建食谱时,效果很好,图像是 也添加了,我可以查看它。但是,当我去更新它时 作为

   PersistenceManager pm = PMF.get().getPersistenceManager();
   Recipe r = pm.getObjectById(Recipe.class, recKey);
   try {
       r.setImage(newImage);
   } finally {
       pm.close();
   }

新图像已添加到数据存储中,但是当我尝试获取它时 从食谱中,食谱仍然指向我的旧图像 数据存储。这是正常的吗?我该如何解决这个问题?

这是我的 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>

【问题讨论】:

  • 你有没有想过这个问题?我有同样的问题。希望赏金会有所帮助。
  • @Lumpy,不幸的是,我通过完全抛弃拥有关系以支持无拥有关系来解决此问题。我在网上找不到任何帮助,而且这里的声誉也没有帮助。

标签: java google-app-engine jdo


【解决方案1】:

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

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

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

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

这种令人困惑的混淆是我完全放弃 JDO 和拥有关系并学会爱 Objectify 的原因。它们还限制了您对实体组的选择,这增加了雾的另一个维度。

【讨论】:

  • 是的,不幸的是,我也放弃了应用引擎的 JDO。这是一个标准层,使我的应用程序引擎应用程序可以在谷歌世界之外工作。 objectify 是否在 googlestore 之外工作?
  • 不,Objectify 是 100% 特定于应用程序引擎的 :(
  • 这几乎就是我最终选择的道路。如果不是创建一个新对象,而是获取该对象,更新它,然后存储它,它似乎可以工作。
【解决方案2】:

我认为您必须在设置新图像对象后调用 pm.makePersistent(r); 以实际保留您的更改。

【讨论】:

  • 你能把你jdoconfig.xml的内容贴出来。您是否更改了该文件中的任何内容,尤其是 datanucleus.appengine.autoCreateDatastoreTxns 的值?
【解决方案3】:

不需要pm.makePersistent(r);,因为配方已经持久化。 但是在您的代码示例中,您使用非事务性读取,这意味着您可以在没有事务的情况下从数据存储中读取实例。 但是,如果您想进行持久修改,则需要使用 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();
   }

【讨论】:

  • 我也尝试过交易。结果相同。图像已添加到数据存储中,但 Recipe 对象仍指向第一个图像。
  • 如果你执行 pm.refresh(r) 会发生什么?
  • tx.commit(); 之前添加。还是一样的结果:(
  • 我认为您不必使用事务来持久化对对象的更改。猜想:AppEngine 只是在您关闭 pm 时对您更改的对象调用 put
【解决方案4】:

对我有用的是获取需要更新的旧对象,然后更改对象然后存储它。调整你的代码给我们:

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

这基本上是我所做的,并且似乎有效。

【讨论】:

  • 不需要在已经持久化的对象上调用 makePersistent;关闭 PersistenceManager 应该可以完成保存更改的工作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 2013-09-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多