Pergunta

Estou tendo dificuldade para descobrir a maneira correta de atualização "aninhados" dados usando o Google App Engine e JDO. Eu tenho um RecipeJDO e um IngredientJDO .

Eu quero ser capaz de completamente substituir os ingredientes em uma determinada ocorrência de receita com uma nova lista de ingredientes. Em seguida, quando a receita é (re) persistiu, ingredientes qualquer previamente ligados serão eliminados totalmente a partir do armazenamento de dados, e os novos serão persistiu e associada com a receita.

Algo como:

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

Isso funciona bem quando eu atualizar (independente) receita objetos diretamente, como retornado do armazenamento de dados. No entanto, se eu cópia a RecipeJDO, em seguida, fazer as alterações acima referidas, acaba por acrescentar novos ingredientes, que são depois devolvidos juntamente com os ingredientes de idade, quando a receita é então re-buscada a partir do armazenamento de dados. (Por que se preocupar com a cópia em tudo? Eu estou usando GWT no front-end, por isso estou copiando o JDO objetos para DTOs, o usuário edita-los no front-end, e então eles são enviados para o servidor para atualizar o armazenamento de dados.)

Por que eu obter resultados diferentes com objetos que crio com a mão (de definir todos os campos, incluindo o id) vs operando em instâncias retornadas pelo PersistenceManager? Obviamente aprimoramento bytecode do JDO está envolvido de alguma forma.

Am I melhor apenas excluindo explicitamente os antigos ingredientes antes persistem o atualizados receita?

(Side questionário faz ninguém ficar frustrado com ORM e desejo, poderíamos voltar para RDBMS antigos simples: -?)

Foi útil?

Solução

A resposta curta. Mudança RecipeJDO.setIngredients() a esta:

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

Quando você buscar o RecipeJDO, a lista ingredients não é um verdadeiro ArrayList, é um proxy dinâmico que manipula a persistência dos elementos contidos. Você não deve substituí-lo.

Enquanto o gerenciador de persistência é aberto, você pode percorrer a lista ingredients, adicionar itens ou remover itens, e as alterações serão persistiu quando o gerenciador de persistência está fechado (ou a transação é confirmada, se você estiver em uma transação) . Veja como você faria a atualização sem uma transação:

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

Se você nunca modificar os objetos IngredientJDO (somente substituí-los e lê-los), você pode querer torná-los Serializable objetos em vez de JDO objetos. Se você fizer isso, você pode ser capaz de reutilizar a classe Ingredient em seu código GWT RPC.

Aliás, mesmo se Recipe não era um objeto JDO, você iria querer fazer uma cópia no método setIngredients(), caso contrário, alguém poderia fazer isso:

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

Outras dicas

Eu estou enfrentando o mesmo problema! Gostaria de atualizar uma entidade existente, chamando makePersistent () e atribuir um ID / chave existente! a atualização funciona bem, exceto para objetos aninhados! Os objetos aninhados são anexados aos antigos em vez de ser substituído? Eu não sei se este é o comportamento desejado ou se este é um bug? I esperar substituir a ter o mesmo efeito que a inserção de uma nova entidade!

Como cerca de primeiro apagar a entidade de idade e persistindo o novo na mesma transação? Isto funciona? Eu tentei isso, mas resultou em excluir a entidade completamente ?! Eu não sei por que (mesmo que eu tentasse liberar diretamente após a exclusão)!

@NamshubWriter, não tenho certeza se você vai pegar esse post ... sobre o seu comentário,

(se você usou listras e JSP, você poderia evitar os GWT RPC e GWT representações de modelo de receita e Ingredient)

I am com listras e JSP, mas enfrentam o mesmo problema. Quando o usuário envia o formulário de volta, listras instancia minha objetos de entidade a partir do zero, e assim por JDO é completamente ignorante deles. Quando eu chamar PersistenceManager.makePersistent no objeto raiz, a versão anterior é correctamente substituído - com uma exceção, seus criança objetos são Em anexo à List da versão anterior.

Se você poderia sugerir qualquer solução (melhor do que copiar manualmente os campos de objeto) eu agradeceria muito.

(vendo como Stripes é tão pluggable, eu me pergunto se eu posso substituir como ele instancia os objetos de entidade ...)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top