Hibernate + atualizacao da chave primaria

O meu sistema tem uma tabela com quatro chaves primárias (data, hora, idcolaborador, idvisitante). Estou tentando atualizar estas chaves porém é mostrado o seguinte erro! tenho certeza que este erro é decorrente da atualização da chave, mas, não sei como solucionar conto com sua ajuda

Quando me refiro a atulização da chave, quero dizer que troco os dados da chave por outros dados diferentes.

log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version).
log4j:WARN Please initialize the log4j system properly.
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
	at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
	at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
	at org.hibernate.jdbc.BatchingBatcher.checkRowCounts(BatchingBatcher.java:68)
	at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:48)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:242)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:235)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:140)
	at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
	at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
	at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:338)
	at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:106)
	at src.portaria.dao.ColaboradorDAO.update(ColaboradorDAO.java:54)
	at src.portaria.gui.Tela_manterColaborador.altera_registro(Tela_manterColaborador.java:454)
	at src.portaria.gui.Tela_manterColaborador.bsalvar(Tela_manterColaborador.java:386)
	at src.portaria.gui.Tela_manterColaborador$3.actionPerformed(Tela_manterColaborador.java:270)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.Dialog$1.run(Unknown Source)
	at java.awt.Dialog$2.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.awt.Dialog.show(Unknown Source)
	at java.awt.Component.show(Unknown Source)
	at java.awt.Component.setVisible(Unknown Source)
	at src.portaria.gui.Tela_consultaColaborador.bexibir(Tela_consultaColaborador.java:391)
	at src.portaria.gui.Tela_consultaColaborador$2.actionPerformed(Tela_consultaColaborador.java:166)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.Dialog$1.run(Unknown Source)
	at java.awt.Dialog$2.run(Unknown Source)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.awt.Dialog.show(Unknown Source)
	at java.awt.Component.show(Unknown Source)
	at java.awt.Component.setVisible(Unknown Source)
	at src.portaria.gui.Tela_principal.bmanterColaborador(Tela_principal.java:245)
	at src.portaria.gui.Tela_principal$3.actionPerformed(Tela_principal.java:104)
	at javax.swing.AbstractButton.fireActionPerformed(Unknown Source)
	at javax.swing.AbstractButton$Handler.actionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.fireActionPerformed(Unknown Source)
	at javax.swing.DefaultButtonModel.setPressed(Unknown Source)
	at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(Unknown Source)
	at java.awt.Component.processMouseEvent(Unknown Source)
	at javax.swing.JComponent.processMouseEvent(Unknown Source)
	at java.awt.Component.processEvent(Unknown Source)
	at java.awt.Container.processEvent(Unknown Source)
	at java.awt.Component.dispatchEventImpl(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.LightweightDispatcher.retargetMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.processMouseEvent(Unknown Source)
	at java.awt.LightweightDispatcher.dispatchEvent(Unknown Source)
	at java.awt.Container.dispatchEventImpl(Unknown Source)
	at java.awt.Window.dispatchEventImpl(Unknown Source)
	at java.awt.Component.dispatchEvent(Unknown Source)
	at java.awt.EventQueue.dispatchEvent(Unknown Source)
	at java.awt.EventDispatchThread.pumpOneEventForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
	at java.awt.EventDispatchThread.run(Unknown Source)

Esqueci de comentar que estou utilizando o hibernate com annotation.

Outra informação sobre o problema! a chave que estou querendo atualizar é composta. alguém tem alguma sugestão?

Só uma observação

É realmente necessario usar Data e Hora como Chave em sua tabela ?

Sim! Pior que sim paceiro caso contrário já teria retirado a chave. Estou utilizando o SGBD Mysql, tente alterar a chave direto no banco e consegui alterar. Mas através do hibernate isso não está sendo possível, em que é mostrado o erro abaixo.


org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count:

vc tem alguma sugestão?

Cara, esse erro é pq ele não está ‘encontrando’ algum dos ID para atualizar…

Vc já debugou? Antes da linha:

session.update(seu_objeto);

Debuga e ve se o seu_objeto tem a chave primária ou se ela está nula!

E outra coisa, vc tem que ter certeza que está passando um ID existente na tabela ‘pai’.

Depois posta ae :smiley:

obrigado davipadilha! seguinte com faço para debugar uma linha especifica como vc pediu? isso levando em consideração que estou utilizando o eclipse. É só rodar pelo a opção debug do eclipse?

Sim…coloca o breakpoint na linha que vc quer debugar, roda em modo debug e faz o procedimento que chama a linha em questão.

E no seu_objeto, vc clica com o botão direito e vai em watch… e olha se tem algum id diferente de id que existe no banco ou se ele está nulo.

Depurei o código, em que as chaves (objetos) que estou tenta persistir aparecem como nulas!

Eu também estou programando com Hibernate, com annotation, uma coisa que esta me ajudando d + é que configurei o seguinte

SessionFactory sessionFactory = new AnnotationConfiguration() .... .setProperty("hibernate.show_sql","true") .... .configure() .buildSessionFactory();

vc pode fazer isso no hibernate.cfg.xml tb, e setar essa propriedade, que vai fazer o hibernate soltar no console toda linha SQL que ele usa…

Fora isso, pelo que entendi, vc ta tentando recuperar dados do banco, e tua chaves estão vindo como nulas…

Isso ocorreu comigo quando eu tentava criar novos dados no banco, ai as chaves se mantinham nulas, e depois disso não era possivel fazer updates resolvi isso botando o seguinte campo no ID…

[code]package com.jujuba.api.modelo.comum;

import java.io.Serializable;
import java.util.Collection;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import com.jujuba.api.controle.RegistroGenerico;

@Entity
@Table(name=“pessoa”)
public class Pessoa extends RegistroGenerico {
/**
* Número interno do banco de dados de identificação da pessoa.
/
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name=“pessoa_id”)
private int identificacao;
/
*
* Nome da pessoa.
/
@Column(name=“pessoa_nome”,nullable=false,unique=true)
private String nome;
//private Collection<Telefone> telefones;
/
*
* Modifica o número de identificação iterno da pessoa
* @param identificacao número interno de identificação da
* pessoa no banco de dados.
/
public void setIdentificacao(int identificacao) {
this.identificacao = identificacao;
}
/
*
* Busca o número de identificação interno da pessoa no banco de dados.
* @return o número de identificação interno da pessoa no banco de dados.
/
public int getIdentificacao() {
return identificacao;
}
/
*
* Modifica o nome da pessoa
* @param nome nome da pessoa
/
public void setNome(String nome) {
this.nome = nome;
}
/
*
* Busca o nome da pessoa
* @return o nome da pessoa.
*/
public String getNome() {
return nome;
}
@Override
protected Serializable getRegistroGenericoID() {
return this.getIdentificacao();
}

public String toString()
{
	return this.getNome();
}

}[/code]

Note essa parte do código…

... @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name="pessoa_id") private int identificacao ...

Com ela eu aviso ao Hibernate, que minha chave é gerada pela tabela, de forma automática, e quando eu faço algo como session.save(pessoa) ai ele adciona no banco, e ja seta a minha chave primaria…

Não sei o motivo exato de tuas chaves estarem vindo nulas, mais pode ser isso…

 package src.portaria.vo;

import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;

import javax.persistence.Table;

@Entity
@Table(name = "registrar_visita")
public class RegistrarVisita{
	
	@EmbeddedId
	private IdRegistrarVisita idRegVis;
	private String Reg_status;
	private String Reg_horaSaida;	
	private String Reg_obsGeral;
	private String Reg_usuarioLogado;
	
	@ManyToOne
	@JoinColumn(name = "Reg_Set_codigo", insertable=true, updatable=true, nullable = false)
	private Setor setor;
	
	
	
	public RegistrarVisita(){
		
	}



	public IdRegistrarVisita getIdRegVis() {
		return idRegVis;
	}



	public void setIdRegVis(IdRegistrarVisita idRegVis) {
		this.idRegVis = idRegVis;
	}



	public String getReg_horaSaida() {
		return Reg_horaSaida;
	}



	public void setReg_horaSaida(String reg_horaSaida) {
		Reg_horaSaida = reg_horaSaida;
	}



	public String getReg_obsGeral() {
		return Reg_obsGeral;
	}



	public void setReg_obsGeral(String reg_obsGeral) {
		Reg_obsGeral = reg_obsGeral;
	}



	public String getReg_usuarioLogado() {
		return Reg_usuarioLogado;
	}



	public void setReg_usuarioLogado(String reg_usuario) {
		Reg_usuarioLogado = reg_usuario;
	}



	public String getReg_status() {
		return Reg_status;
	}



	public void setReg_status(String reg_status) {
		Reg_status = reg_status;
	}



	public Setor getSetor() {
		return setor;
	}



	public void setSetor(Setor setor) {
		this.setor = setor;
	}


	

	
	
}



package src.portaria.vo;


import java.util.Date;
import javax.persistence.Embeddable;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import java.io.Serializable;



@Embeddable
public class IdRegistrarVisita implements Serializable{
	
	private String Reg_horaEntrada;
	
	private Date Reg_dataVisita;	
	
	@ManyToOne
	@JoinColumn(name = "Reg_Vis_codigo", insertable=true, updatable=true, nullable = false)
	private Visitante visitante;
	
	@ManyToOne
	@JoinColumn(name = "Reg_Col_codigo", insertable=true, updatable=true, nullable = false)
	private Colaborador colaborador;

	
}

Alguém tem alguma sugestão?

Cara, na época que fiz cadeira de BD já dizia pra escolher uma chave que não mudasse, ou que raramente o fizesse. Se nenhum dos atribudos de sua tabela cumpre esse requisito, é melhor criar um atributo que vai servir apenas como PK. Algumas razões para fazer isso:

  1. Consistência. Se sua tabela se relaciona com outras e PK mudar, se nao for feito um tratamento adequado esse BD provavelmente vai ficar inconsistente.

  2. OverHead de processamento. Suponha que vc use como PK de um cliente que realiza compras. Suponha que vc link o cliente com as compras que vez, colocando a PK do cliente no produtos que ele comprou. Suponha que ele tenha comprado muitos produtos. Aí qdo vc fosse atualizar o nome do cliente, teria que atualizar todas as FK de seus respectivos produtos. Imagine o OverHead disso, se muito pessoas atualizarem o nome.

Enfim, como boa prática, eu sempre crio minhas PK de forma que ela não tenha nenhum significado para as regras de negócio, servido apenas para identificação da entidade, evitando assim os problemas que descrevi.

Mas vamos ver o que o pessoal com mais experiência acha…

então renzonuccitelli, foi exatamente o q sugeri pra ele…

o problema ate onde ele tinha me dito, era q não keria replicas no registro (quando os 4 campos q ele ta usnado como chave são iguais), neste caso sugerir pra ele fazer um UNIQUE na tabela pros campos, e criar 1 chave primaria, assim ele poderia alterar normalmente seus dados.

Lavieri, concordo com vc. Ainda digo mais, para os beans relativos ao banco de dados, costumo criar uma interface, que chamo de Codificavel. Essa interface possui o método long getCodigo(). Assim, todos os meus beans a implementam, e isso permite que eu use um DAO generico para opercoes simples, como criar, salvar e artualizar no bd…
Acho que o problema está mais no conceito de BD mesmo.

Obrigado a todos pela contribuição principalmente pelo Lavieri esse cara é fera! Acho errado essa solução que foi dada mais vou utilizar ela temporariamente até encontrar uma forma melhor de atualizar as chaves. A solução sugerida aqui é funciona mais vai contra os principios de banco de dados porque não posso sair colocando ID em todas as tabelas para isso serve as chaves primarias estrangeiras compostas.

Não estou criticando de forma alguma os colegas pelo contrario só tenho a agradecer por tudo. Mais deixo claro que vou continuar em busca da solução para esse problema quando encontrar vou postar neste tópico.

Abraços!

Lavieri, parceiro funcionou a forma com vc me disse! obrigado pela ajuda! Espera a ter mais contriuições para encontrar a melhor forma de resolver
esse problema que muitos desenvolvedores tem! Por isso conto com a experiência e conhecimento de mais pessoas! valeu

eu acabei de fazer aki, com chaves compostas estrangeiras, e funciona tb… o fato é q chave primária não deve ser modificada, e se há itenção de modificação a melhor solução é a criação de 1 chave interna, e se a unica intenção é que não haja replicas, fazer um unique …

O que vc tava kerendo fazer, pelo q entendi, era alterar a chave primaria atravez do hibernate, o que nunca iria acontecer, visto q ele cria a codição WHERE do update de acordo com a chave primária …