Hibernate x Update

Pessoal, tenho um entidade com N atributos:

@Entity
@Table(name="tabela")
@SequenceGenerator(name = "sequence", sequenceName = "sequence", allocationSize = 1)
public class Banco_Dados {

	@Id
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
	private Long id;
	
	private String 	 campo A;
	
	private String 	 campo B;

        private Integer campo C;
      
        private Integer campo D;

        private Integer campo E;

       ....

Em algum lugar da minha página faço um UPDATE setando apenas um atributo, por exemplo:

quando faço isso ele faz o Update deste campo, mas grava NULL para os outros que não foram setados!!! já tentei com Merge e UpdateOrSave, mas ambos ocorre o mesmo problema.

Como devo tratar isso ?? pra ele fazer o update dos campos setados e manter os valores dos campos que não foram setados no parâmetro ??

Grato.

Bom dia.
Quando voce busca algum dado do BD atravez do Hibernate voce passa como parametro um identificador que creio eu ser o seu ID. Bem com isso quando voce carrega o dado objeto na sessao e atualiza este objeto mudando apenas um atributo voce nao precisa dar um comando save ou saveOrUpdate. O proprio objeto em cache atualiza automaticamente no banco ja que a transacao esta aberta.
Veja isso…

session = new HibernateUtil().getSession();
Transaction tx = session.beginTransaction();
Item item = new Item();
item = (Item)session.get(Item.class, 22L);
item.setDesconto(33.0);

tx.commit();
session.close();

Espero ter te ajudado e se acaso eu estiver errado, por favor me avisem… obrigado…
Ate mais.

Tentei fazer apenas dando commit mas não funcionou !!! Também tentei usar a anotação @org.hibernate.annotations.Entity(
optimisticLock = OptimisticLockType.ALL , dynamicUpdate = true)
na minha Entidade, mas também não funcionou!!! :cry:

Acho melhor por meus métodos aqui:

DAO Genérico:

public void atualiza(T u){
	this.session.merge(u);
}

Logic:

public void update(Entidade entidade){		
	this.daoFactory.beginTransaction();
	this.daoFactory.getEntidadeDao().atualiza(entidade);
	this.daoFactory.commit();
}

JSP:

<input type="checkbox" onclick="window.location='tabela.update.logic?entidade.campoD=1'" /> 

Ah, além do hibernate, estou usando VRaptor !!!

Alguma luz no final do túnel ??

Grato.

Se você quer dar um update num registro que ja existe se você não der um load (ou get como o colega ja falou) é claro que ele vai por null no resto.

afinal ele vai achar que vocÊ quer atualizar o resto pra null.

tente na hora de atualizar antes no seu logic, carregar o entity alterar o campo que você quer alterar e ai sim salvar

Só uma dúvida, se eu fizer um load depois eu não tenho que sair setando atributo por atributo ??? se sim, no caso da tabela ter 200 campos, fica meio complicado fazer isso !!! Como no meu caso, onde o VRaptor seta os atributos de acordo com os parametros passados, como no exemplo que citei do checkbox ??

   public void update(Entidade entidade){        
       this.daoFactory.beginTransaction();  
       this.daoFactory.getEntidadeDao().atualiza(entidade);  
       this.daoFactory.commit();  
   }  

   public Entidade getEntidade(){
            return entidade;
   }

Bem, em todo caso como se encaixaria o load usando o código acima ??

Grato.

claro que não tem, se não não teria sentido nenhum usar esse frame work :slight_smile: era melhor fazer na unha :smiley:

Só complementando quadno você da um load ou get (le na doc que tem diferença) é o mesmo que você tivesse dado um select na tabela e carregado todas as propriedades do objeto.

acho que você deveria ler uns tutoriais de Hibernate (ou outro framework), para consolidar melhor algumas ideias

[quote=ddduran]Só complementando quadno você da um load ou get (le na doc que tem diferença) é o mesmo que você tivesse dado um select na tabela e carregado todas as propriedades do objeto.

acho que você deveria ler uns tutoriais de Hibernate (ou outro framework), para consolidar melhor algumas ideias[/quote]

Vou dar uma lida sim mais profunda na documentação, inclusive acabei de comprar um livro, mas não cheguei na parte de hibernate ainda !!

Mas enquanto isso, me ajude por favor…

Se eu fizer assim:

 public void update(Entidade entidade){          
     entidade = this.daoFactory.getEntidadeDao().loadRegistro(entidade.getId_entidade());
     this.daoFactory.beginTransaction();    
     this.daoFactory.getEntidadeDao().atualiza(entidade);    
     this.daoFactory.commit();    
 }    
   
 public Entidade getEntidade(){  
          return entidade;  
 } 

Ele recupera o objeto no banco e ignora os novos valores passados por parametros !!! consequência: não persiste a alteração desejada !!

O que estou fazendo de errado ??

Valew.

quando você ta dando o load você está realmente sobreponto suas informações com as que estão no banco.

vo tem que fazer assim

1 - o load não estaria dentro do seu metodo update mas sim no componente que chama o metodo update
2 - antes de atribuir os novos valores você da um load nesse objeto
3 - depois você muda os valores da sua entidade
4 - executa o metodo update

algo como isso


MinhaEntidade entidade = dao.loadRegistro(idInjetadoPeloVraptor);
entidade.setAtributoQueQueroAlterar(valorInjetadoPeloVraptor);

// e assim para todos os atributos que quero alterar
 ...

dao.update(entidade);

t.commit();

um conselho paralelo, evite dar o commit dentro do seu metodo update, por que isso impediria você usar transações efetivamente

Cara, desculpa vi agora que esse metodo update não é um metodo de DAO e sim o metodo que vai ser chamado pelo VRaptor, ne?
então ficaria assim:

public void update(Entidade entidade){             
    Entidade e = this.daoFactory.getEntidadeDao().loadRegistro(entidade.getId_entidade());   
    e.setAtributoQueQueroAlterar(entidade.getAtributoQueQueroAlterar());
    // e assim vai
    ....
    this.daoFactory.beginTransaction();       
    this.daoFactory.getEntidadeDao().atualiza(entidade);       
    this.daoFactory.commit();       
}       
     
public Entidade getEntidade(){     
         return entidade;     
} 

Por favor, um pouco de paciência comigo !!! rsrsrsrsrs

Então, dessa maneira que está seu código mostra justamente aquele problema que falei anteriormente, de ficar setanto atributo por atributo. Ai que pega, pois posso alterar 1 atributo como 200… isso é dinâmico !!!

E na verdade, o public void update é o componente, o método está no Dao Genérico, como postei anteriormente.

Valew.

hehehe desculpa não queria passar impaciencia.

poxa que problemão heim colega?

eu não me recordo de cabeça se um dos metodos do hibernater de atualização (merge, sabe, update, perisist) tem a caracteristicas de atualizar
ignorando campos nulos :confused: realmente nesse momento decepciono-me como desenvolvedor :stuck_out_tongue:

mas vamos ver, no seu Entity, todos os campos dele não estão no seu formulario anterior?
vai lhe custar tanto assim à manutenção você estipular os campos que serão atualizados?

o seu “Entidade”, não contem o estado correto atual do objeto? você pode simplesmente persistilo.

uma ultima alternativa seria o seguinte, você ao inves de receber como parametro do metodo seu “Entidade”, coloque ele como um atributo do seu componente e deixe ele com escopo de sessão.
Se você está editando um certo elemento do seu banco de dados significa que em algum momento você já o carregou. (logo ele vai estar carregado na sua sessão)

logo quando o VRAPTOR for chamar esse seu metodo (update) ele vai alterar apenas os campos que você tem parametro na requisição
e você poderá persisti-lo.

Não sei se ficou claro esse ultimo, mas acho que seria uma boa solução

Então, para vc visualizar melhor como estou usando a session (Seguindo a apostila sobre VRaptor e Hibernate da Caelum) vou postar os códigos aqui:

DaoFactory:

public class DaoFactory {
	
	private final Session session;
	private Transaction transaction;
	
	public DaoFactory(){
		session = HibernateUtil.getSession();
	}
	
	public void beginTransaction(){
		this.transaction = this.session.beginTransaction();
	}
	
	public void commit(){
		this.transaction.commit();
		this.transaction = null;
	}
	
	public boolean hasTransaction(){
		return this.transaction != null;
	}
	
	public void roolback(){
		this.transaction.rollback();
		this.transaction = null;
	}
	
	public void close(){
		this.session.close();
	}
        
        /*Modelos*/
        public Dao<Entidade> getEntidadeDao(){
		return new Dao<Entidade>(this.session, Entidade.class);
	}
}

DAO (Genérico)

package sensatta.dao;

import java.util.List;
import org.hibernate.Session;

public class Dao<T> {

	protected 	final Session 	session;
	private 	final Class 	classe;
	
	Dao(Session session, Class classe){
		this.session = session;
		this.classe  = classe;
	}
	
	public void adiciona(T u){
		this.session.save(u);
	}
	
	public void altera(T u){
		this.session.flush();
		this.session.clear();
		this.session.update(u);
	}
	
	public void remove(T u){
		this.session.delete(u);
	}
	
	public void atualiza(T u){
		this.session.merge(u);
	}
	
	@SuppressWarnings("unchecked")
	public List<T> listaTudo(){
		return this.session.createCriteria(this.classe).list();
	}
	
	@SuppressWarnings("unchecked")
	public T procura(Long id){
		return (T) session.load(this.classe, id);
	}
	
	protected Session getSession(){
		return session;
	}	
	
}

Teria que mudar alguma coisa nessa estrutura ??

Valew.

Estou enfrentando o mesmo problema em uma aplicação com VRaptor e Hibernate, ninguém mais aqui já passou por isso?

Obrigado

Analisando bem o causador desse problema é o VRaptor !!! veja, eu tenho no meu request apenas 1 atributo, que pertence a uma entidade com N atributos, o VRaptor seta NULL para todos os outros atributos que não estão no meu request, e como NULL é considerado um valor, o Hibernate compara que NULL <> valor antigo, então grava !!!

Um exemplo do que estou falando é o mentawai, lá se eu tenho uma Entidade com 100 atributos e em algum lugar do meu sistema eu tenho um FORM com apenas 10 desses 100 atributos ele altera apenas esses 10 sem eu ter que ficar recuperando o objeto da sessão e sair setando os 10 atributos para depois persistir.

Alguém conhece bem o VRaptor e sabe como resolver este problema ??

Valew.

e ai, alguem sabe como foi resolvido esse problema?

estou passando pelo mesmo problema!