atualizar “aninhados” objetos com JDO no Google App Engine
-
18-09-2019 - |
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: -?)
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
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 ...)