Java 更新「;嵌套的;在Google App Engine上使用JDO的对象

Java 更新「;嵌套的;在Google App Engine上使用JDO的对象,java,google-app-engine,orm,jdo,Java,Google App Engine,Orm,Jdo,我很难找到使用谷歌应用程序引擎更新“嵌套”数据的正确方法 还有JDO。我有一个和一个 我希望能够用新的配料列表完全替换给定配方实例中的配料。然后,当配方被(重新)持久化时,任何先前附加的成分都将从数据存储中完全删除,新的成分将被持久化并与配方关联 比如: // retrieve from GAE datastore RecipeJDO recipe = getRecipeById(); // fetch new ingredients from the user Lis

我很难找到使用谷歌应用程序引擎更新“嵌套”数据的正确方法 还有JDO。我有一个和一个

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

比如:

  // 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);
//从GAE数据存储中检索
RecipeJDO recipe=getRecipeById();
//从用户处获取新配料
列出新成分=GetNewComponents();
配方。设置配料(新配料);
//使用新成分更新配方
saveUpdatedRecipe(配方);
当我直接更新(分离)从数据存储返回的配方对象时,这可以很好地工作。但是,如果我复制一个RecipeJDO,然后进行上述更新,它最终会添加新成分,然后在从数据存储中重新获取配方时,这些成分会与旧成分一起返回。(为什么还要麻烦复制呢?我在前端使用GWT,所以我将JDO对象复制到DTO,用户在前端编辑它们,然后将它们发送到后端以更新数据存储。)

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

我是不是最好在坚持更新之前直接删除旧成分 食谱


(附带问题-是否有人对ORM感到失望,并希望我们能回到简单的旧RDBMS?:-)

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

public void setIngredients(List<IngredientJDO> ingredients) {
  this.ingredients.clear();
  this.ingredients.addAll(ingredients);
}
如果从不修改
IngredientJDO
对象(仅替换并读取它们),则可能希望将它们设置为可序列化的
对象,而不是JDO对象。如果这样做,您可能能够在GWT RPC代码中重用
成分

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

List<IngredientJDO> ingredients = new ArrayList<IngredientJDO>;
// add items to ingredients
recipe.setIngredients(ingredients);
ingredients.clear(); // Woops! Modifies Recipe!
List components=new ArrayList;
//添加项目的成分
配方.配料(配料);
成分。清除();//呜呜!修改配方!

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


先删除旧实体,然后在同一事务中保留新实体,怎么样?这行吗?我试过了,但结果是完全删除了实体?!我不知道为什么(即使我在删除后直接尝试刷新)

@NamshubWriter,不确定你是否能赶上这篇帖子。。。关于你的评论,

(如果使用Stripes和JSP,可以避免配方和配料的GWT RPC和GWT模型表示)

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

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


(由于条纹是如此可插拔,我想知道是否可以覆盖它如何实例化实体对象…

抱歉,这并不能解决问题。我说得不太清楚。当我从GWT获得(非JDO)配方时,我创建新的RecipeJDO对象(我字面上称为“new RecipeJDO()”),复制中的所有字段,然后对其执行pm.makePersistent()。是通过“新”的创造造成了问题。如果我改为从数据存储中获取RecipeJDO,然后将字段复制到中,则一切正常。我认为解决方案是从数据存储中获取旧的RecipeJDO,将字段复制到该对象中,然后更新该对象。SQL一直看起来更好。;-)如果要更新现有配方,请不要创建新的RecipeJDO对象。创建新的ReceipeJDO对象并调用makePersistent()就像执行SQL插入一样。在首次创建配方时,已插入数据。之后,您应该更新它。是的,但是我正在将RecipeJDO的id设置为数据存储中现有配方的id,因此它应该作为一个更新。确实如此,除了(新)成分被添加到现有成分的列表中,而不是替换它们。似乎我需要从PersistenceManager中检索RecipeJDO,更新其字段,删除任何现有成分(使用其原始列表),然后添加新成分,然后重新持久化它。虽然这可能会满足我的需要,但似乎需要做大量的工作,这首先会否定ORM的实用性。唯一的额外工作是从PersistenceManager获得ReceipeJDO,而不是由构造函数创建它。您必须将RecipeJDO上的字段从GWT RPC DTO设置为任意一种方式。正如我在回答中所说,删除setComponents()中的现有成分是您无论如何都要做的事情。在配方表示之间复制代码的需要更多地是GWT的功能,而不是JDO的功能(如果使用Stripes和JSP,可以避免
List<IngredientJDO> ingredients = new ArrayList<IngredientJDO>;
// add items to ingredients
recipe.setIngredients(ingredients);
ingredients.clear(); // Woops! Modifies Recipe!