2

我无法找出使用 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 吗?:-)

4

3 回答 3

4

简短的回答。改成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 对象。如果您这样做,您可能能够Ingredient在您的 GWT RPC 代码中重用该类。

顺便说一句,即使Recipe不是 JDO 对象,您也需要在setIngredients()方法中制作副本,否则有人可以这样做:

List<IngredientJDO> ingredients = new ArrayList<IngredientJDO>;
// add items to ingredients
recipe.setIngredients(ingredients);
ingredients.clear(); // Woops! Modifies Recipe!
于 2009-09-27T02:57:24.270 回答
0

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

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

于 2010-03-08T10:36:40.477 回答
0

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

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

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

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

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

于 2010-08-15T18:21:49.800 回答