【问题标题】:updating "nested" objects with JDO on Google App Engine在 Google App Engine 上使用 JDO 更新“嵌套”对象
【发布时间】:2023-04-06 19:39:02
【问题描述】:

我无法找出使用 Google App Engine 更新“嵌套”数据的正确方法 和 JDO。我有一个RecipeJDO 和一个IngredientJDO

我希望能够用新的成分列表完全替换给定配方实例中的成分。然后,当该配方被(重新)持久化时,任何先前附加的成分都将从数据存储中完全删除,新的成分将被持久化并与该配方相关联。

类似:

  // retrieve from GAE datastore
  RecipeJDO recipe = getRecipeById();    

  // fetch new ingredients from the user
  List<IngredientJDO> newIngredients = getNewIngredients();
  recipe.setIngredients(newIngredients);

  // update the recipe w/ new ingredients
  saveUpdatedRecipe(recipe);

当我直接更新(分离)配方对象时,这工作正常,从数据存储返回。但是,如果我复制一个RecipeJDO,然后进行上述更新,它最终会附加新成分,然后在从数据存储区重新获取配方时与旧成分一起返回。 (为什么还要麻烦复制?我在前端使用 GWT,所以我将 JDO 对象复制到 DTO,用户在前端对其进行编辑,然后将它们发送到后端进行更新数据存储。)

为什么我手动创建的对象(设置所有字段,包括 id)与对 PersistenceManager 返回的实例进行操作会得到不同的结果?明显地 JDO 的字节码增强以某种方式参与其中。

我最好在坚持更新之前明确删除旧成分 食谱?

(附带问题 - 有没有其他人对 ORM 感到沮丧并希望我们可以回到普通的旧 RDBMS?:-)

【问题讨论】:

    标签: java google-app-engine orm jdo


    【解决方案1】:

    简短的回答。将RecipeJDO.setIngredients() 更改为:

    public void setIngredients(List<IngredientJDO> ingredients) {
      this.ingredients.clear();
      this.ingredients.addAll(ingredients);
    }
    

    当您获取RecipeJDO 时,ingredients 列表不是真正的ArrayList,它是处理所包含元素的持久性的动态代理。你不应该替换它。

    当持久性管理器打开时,您可以遍历ingredients 列表,添加项目或删除项目,当持久性管理器关闭(或事务提交,如果您在交易)。以下是在没有事务的情况下进行更新的方法:

    public void updateRecipe(String id, List<IngredientDTO> newIngredients) {
      List<IngredientJDO> ingredients = convertIngredientDtosToJdos(newIngredients);
      PersistenceManager pm = PMF.get().getPersistenceManager();
      try {
        RecipeJDO recipe = pm.getObjectById(RecipeJDO.class, id);
        recipe.setIngredients(ingredients);
      } finally {
        pm.close();
      }
    }
    

    如果您从不修改IngredientJDO 对象(仅替换它们并读取它们),您可能希望使它们成为Serializable 对象而不是JDO 对象。如果您这样做,您也许可以在您的 GWT RPC 代码中重用 Ingredient 类。

    顺便说一句,即使Recipe 不是 JDO 对象,您也希望在 setIngredients() 方法中进行复制,否则有人可以这样做:

    List<IngredientJDO> ingredients = new ArrayList<IngredientJDO>;
    // add items to ingredients
    recipe.setIngredients(ingredients);
    ingredients.clear(); // Woops! Modifies Recipe!
    

    【讨论】:

    • 对不起,这并不能解决问题。我没有很好地表达它。当我从 GWT 取回(非 JDO)配方时,我创建了新的 RecipeJDO 对象(我实际上称之为“new RecipeJDO()”),复制所有字段,然后对其执行 pm.makePersistent()。是通过“新”创建导致问题。如果我改为从数据存储中获取 RecipeJDO,然后将字段复制进去,一切都很好。我想解决方案是从数据存储中获取旧的 RecipeJDO,将字段复制到 THAT OBJECT,然后更新 THAT OBJECT。 SQL 一直看起来更好。 ;-)
    • 如果您要更新现有配方,请不要创建新的 RecipeJDO 对象。创建一个新的 ReceipeJDO 对象并调用 makePersistent() 就像执行 SQL INSERT。首次创建配方时已插入数据。之后,您应该更新它。
    • 是的,但是我将 RecipeJDO 的 id 设置为数据存储中现有配方的 id,因此它应该作为更新工作。它确实如此,除了(新)成分被添加到现有成分列表中,而不是替换它们。似乎我需要从 PersistenceManager 中检索 RecipeJDO,更新其字段,删除任何现有成分(使用其原始列表),然后添加新成分,然后重新持久化它。尽管这可能会满足我的需要,但似乎大量的工作首先否定了 ORM 的实用性。
    • 唯一的额外工作是通过 ID 从 PersistenceManager 获取 ReceipeJDO,而不是由构造函数创建它。无论哪种方式,您都必须从 GWT RPC DTO 设置 RecipeJDO 上的字段。无论如何,删除 setIngredients() 中的现有成分是您想要做的事情,正如我在回答中所说的那样。与 JDO 相比,recipe 表示之间需要进行代码复制更多的是 GWT 的功能(如果您使用 Stripes 和 JSP,您可以避免使用 GWT RPC 和 GWT 模型表示的 Recipe 和 Ingredient)
    【解决方案2】:

    我也面临同样的问题! 我想通过调用 makePersistent() 并分配一个现有的 id/key 来更新现有的实体!除嵌套对象外,更新工作正常!嵌套对象被附加到旧对象而不是被替换?我不知道这是预期的行为还是错误?我希望覆盖与插入新实体具有相同的效果!

    首先删除旧实体并在同一事务中保留新实体怎么样?这行得通吗?我试过这个,但它导致完全删除实体?!我不知道为什么(尽管我尝试删除后直接刷新)!

    【讨论】:

      【解决方案3】:

      @NamshubWriter,不确定您是否会看到这篇文章...关于您的评论,

      (如果您使用 Stripes 和 JSP,您可以避免使用 GWT RPC 和 GWT 模型表示的 Recipe 和 Ingredient)

      am 使用 Stripes 和 JSP,但我面临同样的问题。当用户返回表单时,Stripes 从头开始​​实例化我的实体对象,因此 JDO 完全不知道它们。当我在根对象上调用 PersistenceManager.makePersistent 时,之前的版本被正确覆盖 - 除了一个例外,它的 child 对象追加List 之前的版本。

      如果您能提出任何解决方案(比手动复制对象字段更好),我将不胜感激。

      (看到Stripes是如此可插拔,我想知道我是否可以覆盖它如何实例化实体对象......)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-01-25
        • 1970-01-01
        • 2023-04-03
        相关资源
        最近更新 更多