Updating "nested" objects with JDO in Google App Engine

I am having trouble finding the proper way to update "nested" data using Google App Engine and JDO. I have RecipeJDO and IngredientJDO .

I want to completely replace the ingredients in this copy of the recipe with a new list of ingredients. Then, when this recipe (re) is saved, any previously attached ingredients will be completely removed from the data store, and new ones will be saved and linked to the recipe.

Something like:

  // 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);

      

This works great when I directly update (detach) the recipe objects returned from the datastore. However, if I copy the retseptJDO, then do the above upgrade, it completes the addition of new ingredients, which are then returned together with the old ingredients, when the recipe is then re-loaded from the data store. (Why bother with copy at all? I use GWT on the front panel, so I copy JDO objects to the DTO, the user edits them on the front panel, and then they are sent to the server to update the datastore.)

Why am I getting different results with the objects I create manually (setting all fields including the ID) and working with the instances returned by the PersistenceManager? obviously the JDO bytecode enhancement is related in some way.

Am I better off just explicitly deleting old ingredients before continuing to update the recipe?

(Side question: is anyone else running into an ORM and wish we could go back to a plain old DBMS? :-)

+2


source to share


3 answers


Short answer. Change RecipeJDO.setIngredients()

to this:

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

      

When you retrieve the RecipeJDO the list is ingredients

not real ArrayList

, it is a dynamic proxy that handles saving the contained items. You don't have to replace it.

While the save manager is open, you can iterate through the list ingredients

, add items or remove items, and the changes will be saved when the save manager is saved (or the transaction is committed if you're in a deal). Here's how you can do an update without a transaction:



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

      

If you never modify objects IngredientJDO

(replace them and read them), you might want to make them Serializable

objects instead of JDO objects. If you do, you can reuse the class Ingredient

in your GWT RPC code.

By the way, even if Recipe

it was not a JDO object, you would like to make a copy in the method setIngredients()

, otherwise someone could do this:

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

      

+4


source


I faced the same problem! I would like to update an existing object by calling makePersistent () and assigning the existing id / key! update works great except for nested objects! Are nested objects being added to old ones instead of replacing? I don't know if this is the intended behavior or is it a bug? I expect overwrite will have the same effect as inserting a new object!



How about first deleting the old object and saving the new one in the same transaction? It works? I tried this but it resulted in the entity being deleted completely ?! I don't know why (although I tried to clean up immediately after deleting)!

0


source


@NamshubWriter, not sure if you will catch this entry ... regarding your comment,

(if you were using Stripes and JSP, you could have avoided the GWT RPC and GWT model views of the recipe and ingredient)

I am using Stripes and JSP but am facing the same problem. When the user submits the form back, Stripes copies the object objects from scratch and therefore the JDO is completely unaware of them. When I call PersistenceManager.makePersistent on the root object, the previous version is overwritten correctly - with one exception, its children are added to the <child> list of the previous version.

If you could suggest any solution (better than manually copying object fields) I would really appreciate it.

(seeing that Stripes is so pluggable, I'm wondering if I can override how it creates entity objects ...)

0


source







All Articles