Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Short answer. Change <code>RecipeJDO.setIngredients()</code> to this:</p> <pre><code>public void setIngredients(List&lt;IngredientJDO&gt; ingredients) { this.ingredients.clear(); this.ingredients.addAll(ingredients); } </code></pre> <p>When you fetch the RecipeJDO, the <code>ingredients</code> list is not a real <code>ArrayList</code>, it is a dynamic proxy that handles the persistence of the contained elements. You shouldn't replace it.</p> <p>While the persistence manager is open, you can iterate through the <code>ingredients</code> list, add items or remove items, and the changes will be persisted when the persistence manager is closed (or the transaction is committed, if you are in a transaction). Here's how you would do the update without a transaction:</p> <pre><code>public void updateRecipe(String id, List&lt;IngredientDTO&gt; newIngredients) { List&lt;IngredientJDO&gt; ingredients = convertIngredientDtosToJdos(newIngredients); PersistenceManager pm = PMF.get().getPersistenceManager(); try { RecipeJDO recipe = pm.getObjectById(RecipeJDO.class, id); recipe.setIngredients(ingredients); } finally { pm.close(); } } </code></pre> <p>If you never modify the <code>IngredientJDO</code> objects (only replace them and read them), you might want to make them <code>Serializable</code> objects instead of JDO objects. If you do that, you may be able to reuse the <code>Ingredient</code> class in your GWT RPC code.</p> <p>Incidentally, even if <code>Recipe</code> was not a JDO object, you would want to make a copy in the <code>setIngredients()</code> method, otherwise someone could do this:</p> <pre><code>List&lt;IngredientJDO&gt; ingredients = new ArrayList&lt;IngredientJDO&gt;; // add items to ingredients recipe.setIngredients(ingredients); ingredients.clear(); // Woops! Modifies Recipe! </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COSorry, this does not solve the problem. I didn't articulate it very well. When I get the (non-JDO) recipes back from GWT, I create new RecipeJDO objects (I literally call "new RecipeJDO()") , copy all the fields in, and then do pm.makePersistent() on it. It's the creation via "new" that is causing the problem. If I instead fetch the RecipeJDO from the datastore, and then copy the fields in, all is well. I suppose the solution is to fetch the old RecipeJDO from the datastore, copy the fields into THAT OBJECT, and then update THAT OBJECT. SQL is looking better all the time. ;-)
      singulars
    2. COIf you are updating an existing recipe, don't create a new RecipeJDO object. Creating a new ReceipeJDO object and calling makePersistent() is like doing an SQL INSERT. The data was already inserted when the recipe was first created. After that, you should update it.
      singulars
    3. COYes, but I'm setting the id of the RecipeJDO to the id of an existing recipe in the datastore, so it should work as an update. And it does, except that the (new) ingredients are added to the list of existing ones, rather than replacing them. It seems like maybe I need to retrieve the RecipeJDO from the PersistenceManager, update its fields, remove any existing ingredients (using its original list), and then add the new ingredients, then re-persist it. Although this will likely do what I need, it seems like an awful lot of work that kind of negates the utility of an ORM in the first place.
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload