我无法找到使用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?: - )
答案 0 :(得分: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对象。如果这样做,您可以在GWT RPC代码中重用Ingredient
类。
顺便说一句,即使Recipe
不是JDO对象,您也希望使用setIngredients()
方法制作副本,否则有人可以这样做:
List<IngredientJDO> ingredients = new ArrayList<IngredientJDO>;
// add items to ingredients
recipe.setIngredients(ingredients);
ingredients.clear(); // Woops! Modifies Recipe!
答案 1 :(得分:0)
我面临同样的问题! 我想通过调用makePersistent()并分配一个现有的id / key来更新现有实体!除嵌套对象外,更新工作正常!嵌套对象是否附加到旧对象而不是被替换?我不知道这是否是预期的行为,或者这是一个错误?我希望覆盖与插入新实体具有相同的效果!
如何首先删除旧实体并在同一事务中保留新实体?这有用吗?我尝试了这个,但它导致完全删除了实体?!我不知道为什么(即使我在删除后尝试直接刷新)!
答案 2 :(得分:0)
@NamshubWriter,不确定你是否会收到这篇文章...关于你的评论,
(如果您使用Stripes和JSP,则可以避免配方和成分的GWT RPC和GWT模型表示)
我是使用Stripes和JSP,但我遇到了同样的问题。当用户提交表单时,Stripes从头开始实例化我的实体对象,因此JDO完全不知道它们。当我在根对象上调用PersistenceManager.makePersistent时,前一版本被正确覆盖 - 除了一个例外,其子对象追加到 List&lt; child&gt; 以前的版本。
如果您可以建议任何解决方案(比手动复制对象字段更好),我将不胜感激。
(看作Stripes是如此可插拔,我想知道我是否可以覆盖它实例化实体对象的方式......)