NonUniqueObjectException - Recuperar id de objeto antes de fazer um update
21/11/2016 00:12
0
Quando você tenta recuperar um atributo de um objeto no banco, para depois salvar, ocorre aquele clássico erro do hibernate:
org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session

No meu caso, em um cadastro do objeto Pessoa, ao digitar o CPF, existe uma consulta Ajax que preenche os dados armazenados, caso existam. E o usuário pode alterar esses dados recuperados de Pessoa antes de salvar.

Então aí vem o problema. Para fazer o update corretamente eu preciso recuperar o id de Pessoa através do CPF, mas ao salvar ocorre o fatídico erro mencionado.

Já tentei preencher o id no retorno do AJAX em um hidden para não ter que recuperar de novo, porém caso seja uma Pessoa nova, o hidden do id fica nulo e por isso o Grails apaga todas as informações preenchidas em Pessoa ao enviar o objeto da tela para o controller.

Ainda não vi uma forma interessante de contornar essa situação. Como vocês fazem nesse caso?
Tags: Grails NonUniqueObjectException


0
Olá Victor.
Primeiramente seria interessante ter uma ideia da sequência de telas que você deseja seguir. Se pudesse colar os printscreens, seria útil.
De uma forma geral, quando recupero um registro do banco  MEUDOMÍNIO.findByCPF (meuCPF), faço o direcionamento da aplicação para a tela de edição ou de exibição apenas - talvez seu aplicativo ainda esteja no âmbito do CREATE, e quando você acessa a funcionalidade SAVE, a aplicação vai tentar gerar um novo registro com aqueles dados recuperados.
Atente que no controller do domínio existem métodos para CREATE, LIST, EDIT, SHOW... todos com suas peculiaridades.
Não sei se ajudei ou se fui muito trivial para o seu caso.
29/11/2016 09:46


0
Vou tentar explicar melhor:

O cenário é apenas uma tela de CREATE.

Imagine que eu tenha um cadastro de solicitação, e antes eu tenha um formulário de solicitante. Os dados desse solicitante já podem estar armazenados (cadastrados em uma outra solicitação por exemplo).
Ao preencher o CPF, o sistema preenche os dados do solicitante caso já existam esses dados (via ajax). Mas o usuário pode atualizar essas informações trazidas do banco. Ou seja, ao salvar a solicitação eu terei um "save solicitante" ou posso ter um "update solicitante".

Sendo assim, nos casos de "save solicitante" eu tenho que enviar o objeto Solicitante preenchido e com id nulo, o no "update solicitante" o objeto deve ter o seu id preenchido.

Segue um exemplo para ilustrar:


0
OBS: A tela é um cadastro de solicitação, porém como nessa mesma tela eu tenho um formulário de solicitante, ao salvar a solicitação eu acabo tento que fazer também o "save ou update" de solicitante na mesma transação.


0
Vc deixa o id como um campo hidden no formulario. Quando for um objeto já existente, o id estará preenchido, quando for novo o id estará nulo.
Quando o grails for fazer o databind no controller ele irá enxergar isso: Se o id estiver preenchido ele vai carregar o objeto do banco e depois aplicar os dados que vieram no request. Se o id estiver vazio ele cria um novo objeto e aplica os dados do request em cima deste.
Na hora de dar save em cima deste objeto, vc vai ter o insert ou update conforme for apropriado.


0
Magno, tentei exatamente essa solução mas não é dessa forma que o Grails está se comportando.

Quando o ID do "hidden" é vazio, o objeto chega no controller com todos os campos nulos (ou seja, ele sobrescreve com null todos os valores preenchidos no formulário).


0
Neste caso o databind não está ocorrendo, se possível nos mostre:
- Os parametros que está recebendo (um println params resolve)
- A declaração da action
- A declaração dos domains e/ou command objects utilizados como argumentos na action


0
Sigo na mesma direção do Magno. Passe essas informações, por favor.
30/11/2016 10:07


0
O databind não está ocorrendo somente quando o hidden consta no html e vazio (sem valor).

Seguem as infos de quando tento realizar o save de solicitação com o hidden "solicitante.id" vazio:

hidden:
<input type="hidden" name="solicitante.id" value=""/>

params:
"solicitante.id" ->
"solicitante" -> size-20
"solicitante.cpf" -> 222.222.222-22
"solicitante.nome" -> "teste"
"solicitante.telefone" -> "(22) 2222-2222"
...

inspect em solicitação:
campos de solicitação preenchidos
solicitante = null (nenhum campo preenchido, não só o id)

   @Transactional
@Secured('permitAll')
def save(Solicitacao solicitacao) {

if (solicitacao == null) { 
transactionStatus.setRollbackOnly()
notFound()
return
  }
// na primeira linha, no if acima, o "solicitante" já é null dentro de "solicitacao".
}


?
class Solicitante {
String nome
String cpf
String cnpj
String registroGeral
String telefone
String celular
String email
Endereco endereco
static hasMany = [solicitacoes:Solicitacao]
static constraints = {
nome nullable: false, blank: false, maxSize: 128
cpf nullable: true, unique: true
cnpj nullable: true, unique: true
registroGeral nullable: true
telefone nullable: false
celular nullable: true
email nullable: true, email: true
endereco nullable: false
}
}
class Solicitacao {
Date dataSolicitacao
Endereco endereco
...
static belongsTo = [solicitante: Solicitante]
static constraints = {
dataSolicitacao nullable: true
endereco nullable: true
solicitante nullable: false
}
}
?


0
Só assim creio que já era para funcionar, mas faça um teste, tente nomear os parametros como solicitacao.solicitante.id, solicitacao.solicitante.cpf, etc


0
Olá.

Vamos começar por seu campo hidden. O seu campo solicitante.id está sem vínculo com a base de dados. É isto mesmo?

Você tem:

<input type="hidden" name="solicitante.id" value=""/>

Tente substituir por:

<g:hiddenField name="solicitante.id" value="${solicitanteInstance?.id}" />
02/12/2016 10:59


0
"O seu campo solicitante.id está sem vínculo com a base de dados. É isto mesmo?"
Não entendi a pergunta Pedro.

Testei com o g:hidden igual você mencionou e o mesmo comportamento foi apresentado. 

OBS: To usando a versão 3.1.8 do grails



Ainda não faz parte da comunidade???

Para se registrar, clique aqui.


Aprenda Groovy e Grails com a Formação itexto!

Newsletter Semana Groovy

Assinar

Envie seu link!


Livro de Grails


/dev/All

Os melhores blogs de TI (e em português) em um único lugar!

 
Creative Commons
RSS Grails Brasil é mantido por itexto Consultoria.
Em caso de problemas contacte Henrique Lobo Weissmann (Kico) por e-mail: kico@itexto.com.br
Todo o conteúdo presente neste site adota o Creative Commons como licença padrão.
Ver: 4.14.0
itexto