Hibernate update/merge

Usando o hibernate 3 qual a solucao que voces indicam para fazer um update de determinados campos de um objeto?

Seria mais o menos o seguinte:
Produto p = new Produto();
p.setId(15L);
p.setNome(“Alterando…”);
s.update§;

O problema do update e hque ele atualizaria tambem o campo ‘descricao’ que eu nao desejo alterar. O proprio merge nao da conta do recado uma vez que o produto que esta sendo utilizado eh um new de Produto.
Alguma sugestao?

Abraco

Guilherme

Vc não pode fazer um load antes? Então se alterar o objeto, quando vc fizer commit o hibernate fará update somente naqueles campos que vc alterou.

Entao ricardo, o problema eh que fazendo o load, na hora de dar o update ele primeiro faz um select no banco. Esse select podefria ser ignorado se eu ja dissesse pra ele quais campos foram alterados. Mas pelo que analisei isso eh impossivel. Vou fazer uma sugestao la

Abraco

Guilherme

Você pode fazer isso extendendo a classe do hibernate que decide isso.

A idéia é simples, quando a entidade sofrer attachment você guarda isso e na hora de verificar quais campos alterar, pega apenas os != null.
Vale lembrar que. Vale lembrar que pra isso funcionar o hibernate tem que estar configurado para gerar update somente para os campos alterados.

A regra do != null eh muito fraca. As vezes eu alterei o campo justamente para null pq quero gravar null no banco de dados…

Acho que a saida eh implementar um metodo do tipo proxyLoad na session, nao sei o nome, sei que esse nome nao eh bom, mas nao sei melhor. Assim:

Produto p = session.proxyLoad(Produto.class, id);

Ai eu chamo os setters desse produto. Com isso, o hibernate (que retornou um objeto adulterado) fica sabendo quais setters eu chamei para fazer o update desses campos.

Chato isso mesmo. Resolvi assim:

  • via AOP, guardo numa Collection quais os campos alterados
  • faço load do Objeto da Database
  • no objeto persistente altero os campos que foram modificados

Resolveu o problema. Quanto ao load “extra” ele já ocorreria pela necessidade de optimistic-locking.

Hmm, essa solução é realmente bem melhor Guilherme, sugere isso pra eles. :wink:

Mapear com dynamic-update não resolve? Do manual:

<editado>Esquece, agora é que vi o seu trecho de codigo.</editado>
valeuz…

Hum, no nosso caso não cara.

Se tenho um objeto com muitas propriedades carregado num formulário e o usuário altera apenas uma informação, da maneira que sugeri preciso enviar para o servidor um objeto apenas com a PK e alteração.

Da forma que sugeriu seria necessário trafegar o objeto inteiro.

Sem contar que o Hibernate não vai cachear as queries, o que também no nosso caso vira um problema.

Noel, no caso ele so iria enviar os campos que foram alterados.

Louds, onde eu sugiro isso la? No jira? Bem que eu podia implementar viu… nunca vi o hibernate por tras, alguem ja colocou a mao nele?

Lipe, o problema eh que a aplicacao eh web, entao nao tenho o objeto persistido por natureza, uma vez que a requisicao eh asincrona. Claro que tenho que levar em conta o problema do locking, nao tinha pensado direito como fazer isso funcionar nesse proxyLoad ou algo do genero.

Tenho duas opcoes: a de sempre, de fazer o load e alterar os campos. Ou a de assumir a responsabilidade. Hummmm… acho que vou tentar a segunda mesmo (pra ter o que fazer por algum tempo)

Valeu gente

Guilherme

Ah … web … :expressionless: medo.

[quote=LIPE]Chato isso mesmo. Resolvi assim:

  • via AOP, guardo numa Collection quais os campos alterados
  • faço load do Objeto da Database
  • no objeto persistente altero os campos que foram modificados

Resolveu o problema. Quanto ao load “extra” ele já ocorreria pela necessidade de optimistic-locking.[/quote]

Fiquei perdidão nesse post !!!

O Hibernate não faz update só nos campos que foram alterados ?

O problema do Guilherme é que o objeto estava detached, então a session não tinha nenhuma informação e gravava tudo.

O que o Guiherme quer é dar um update num registro sem ter que carregá-lo do database, pois o objeto pode ser gigantesco.

E quer dar update só na coluna que ele alterou e não em tudo.

E aí, como resolve isso ?

A solução do Lipe não está fazendo o load do database !?

Sérgio, acho que ficou perdido pois não expliquei que este projeto não é web. Então são objetos (que muitas vezes são bastante grandes) serializados que ficam indo para lá e para cá, não strings no http request.

Um exemplo simples (que nem requeriria a estrutura que estamos utilizando) para esclarecer:

  • cliente pede para o servidor o objeto Pessoa com ID=1
  • Pessoa é passado pela rede e popula o formulário
  • cliente altera o nome da Pessoa
  • cliente envia um objeto Pessoa apenas com o Nome e Id populados para servidor
  • servidor sabe que apenas nome foi alterado
  • servidor pega uma instancia persistente de Pessoa com ID=1 (lembre-se do lazy loading do Hibernate)
  • servidor faz algo como pessoa.setNome( nome )
  • objeto atualizado no banco

Valeu Lipe pela pronta resposta! Ter um Hibernate guru como vc pra me ajudar agora no início é de grande valia. :wink:

O problema está aqui:

Não quero carregar nada do banco de dados.

Quero apenas fazer um update no campo age sem carregar o objeto profile inteiro.

Entendi que isso é perigoso, pois não vou saber se alguma outra transação alterou o campo age também e posso acabar sobre-escrevendo a alteração dela.

Talvez o Hibernate exija esse load sempre para não ter os problemas de concorrência. Sei lá…

E aí? Consigo fazer um update num único campo de um registro sem ter que dar um load nele ou não ?

Nao achei solucao mesmo. Tentei todos os tipos de locking etc e tal.
Vou tentar denovo outro dia, as vezes da alguma ideia genial

hehe que droga guilherme :expressionless:

sérgio, como disse precisamos fazer o select before update de qualquer maneira para pegar o timestamp e informar para o cliente qualquer campo que tenha sido alterado desde que ele carregou aquele registro.

E sério, um selectzinho de nada :smiley: melhor que passar alguns vários kbytes a mais em todo santo update.

Quando queremos fazer o select como o Lipe falou nao tem problema nenhum. O hibernate oferece varios tipos de locking.

Mas quando preciso fazer fine-tuning da aplicacao o select a mais que o hibernate possui para fazer a verificacao da versao ou timestamp deveria ser configuravel.
Tentei a anotacao selectBeforeUpdate=false. Funciona. Ele nao faz o select
Mas ai ele da update em todos os campos.
Ai tentei com selectBU=false e dynamicUpdate=true. Ele nao faz select mas faz update de todos os campos novamente.

Acho que nesse caso de ter uma instancia transiente e ter que dar um update somente nesses campos nao adianta

Guilherme

Yep, por isso a gambiarra com AOP hehe

talvez com merge, selectBU=false, dU = true… vou tentar

nao entendi muito bem a ideia do proxyLoad(…) …

ele traria o objeto apenas com o ID preenchido?

e na hora de enviar o objeto de volta os campos q seriam
enviados, alem dos q foram alterados, iriam ser null, nao sei como isso trafega pela rede, mas acho q pelo fato de ser null, não seriam dados significativos p/ rede …

foi um palpite …