Question

Je vais avoir du mal à déterminer la bonne façon de mettre à jour les données « imbriquées » à l'aide de Google App Engine et JDO. J'ai un RecipeJDO et un IngredientJDO .

Je veux pouvoir complètement remplacer les ingrédients dans une instance de recette donnée avec une nouvelle liste des ingrédients. Ensuite, lorsque la recette est (re) persistait, l'un des ingrédients précédemment attachés seront supprimés totalement à partir de la banque de données, et les nouvelles seront persisté et associés à la recette.

Quelque chose comme:

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

Cela fonctionne bien quand mettre à jour (e) recette objets directement, comme renvoyée par le magasin de données. Toutefois, si I Copier un RecipeJDO, puis faire les mises à jour ci-dessus, il finit par les nouveaux ingrédients annexant, qui sont ensuite retournés en même temps que les anciens ingrédients quand la recette est alors re tirée par les cheveux du datastore. (Pourquoi prendre la peine avec la copie du tout? J'utilise GWT à l'extrémité avant, donc je copier les objets JDO à DTO, l'utilisateur les modifications à l'extrémité avant, puis ils sont envoyés au back-end pour mettre à jour le magasin de données.)

Pourquoi dois-je obtenir des résultats différents avec des objets que je crée à la main (réglage tous les champs, y compris l'id) contre l'exploitation sur les instances renvoyées par le PersistenceManager? Évidemment L'amélioration de bytecode de JDO est impliqué en quelque sorte.

Suis-je mieux juste de supprimer explicitement les anciens ingrédients avant la mise à jour persistant recette?

(question- côté que quelqu'un d'autre se sentent frustrés avec ORM et que vous souhaitez que nous pourrions revenir à la plaine ancienne SGBDR: -?)

Était-ce utile?

La solution

Réponse courte. Changement RecipeJDO.setIngredients() à ceci:

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

Quand vous allez chercher la RecipeJDO, la liste des ingredients est pas un vrai ArrayList, il est un proxy dynamique qui gère la persistance des éléments contenus. Vous ne devriez pas le remplacer.

Alors que le gestionnaire de persistance est ouvert, vous pouvez parcourir la liste des ingredients, d'ajouter des éléments ou supprimer des éléments, et les changements seront persistais lorsque le gestionnaire de persistance est fermé (ou la transaction est validée, si vous êtes dans une transaction) . Voici comment vous feriez la mise à jour sans une 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();
  }
}

Si vous ne modifiez les objets IngredientJDO (seulement les remplacer et de les lire), vous pouvez les fabriquer des objets Serializable au lieu des objets JDO. Si vous faites cela, vous pourriez être en mesure de réutiliser la classe Ingredient dans votre code RPC GWT.

Par ailleurs, même si Recipe était pas un objet JDO, vous voulez faire une copie dans la méthode setIngredients(), sinon quelqu'un pourrait faire ceci:

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

Autres conseils

Je suis face au même problème! Je voudrais mettre à jour une entité existante en appelant makePersistent () et l'attribution d'un identifiant / clé existant! la mise à jour fonctionne très bien à l'exception des objets imbriqués! Les objets imbriqués sont ajoutés aux anciens au lieu d'être remplacé? Je ne sais pas si cela est le comportement prévu ou si cela est un bug? Je me attends d'avoir le remplaçant même effet que l'insertion d'une nouvelle entité!

Que diriez-vous d'abord la suppression de l'ancienne entité et la persistance du nouveau dans la même transaction? Est-ce que ça marche? J'ai essayé cela, mais il a donné lieu à la suppression de l'entité complètement ?! Je ne sais pas pourquoi (même si j'ai essayé nettoyage directement après la suppression)

@NamshubWriter, ne sais pas si vous attrapez ce post ... au sujet de votre commentaire,

  

(si vous avez utilisé Stripes et JSP, vous pouvez éviter les représentations du modèle GWT RPC et GWT de recette et des ingrédients)

am à l'aide Stripes et JSP, mais je fais face au même problème. Lorsque l'utilisateur soumet le formulaire, des bandes de instancie mon entité des objets à partir de zéro, et ainsi JDO est complètement ignorant d'entre eux. Quand j'appelle PersistenceManager.makePersistent sur l'objet racine, la version précédente est remplacée correctement - à une exception près, ses enfant Les objets sont en annexe Liste de la version précédente.

Si vous pouviez proposer une solution (mieux que la copie manuellement les champs d'objet) Je serais très reconnaissant.

(car Stripes est si connectable, je me demande si je peux passer outre la façon dont il instancie les objets entité ...)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top