Problemas List + Hibernate

Pessoal… estou em um dilema.

Vendas / ItemVenda

ao finalizar uma venda, automaticamente possuo um List com minha lista de itens vendidos.
o problema é o segunite!

Se envio uma lista com 1 elemento, tudo certo tudo perfeito.
mas ao enviar uma lista com mais de 1 elemento, PUFF violação de chava

Exception in thread "main" org.hibernate.exception.GenericJDBCException: could not insert collection: [br.com.caelum.hibernate.negocio.entidade.Venda.listaItemVenda#2]
	at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126)
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
	at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1205)
	at org.hibernate.action.CollectionRecreateAction.execute(CollectionRecreateAction.java:58)
	at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:171)
	at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
	at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1028)
	at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:366)
	at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
	at br.com.caelum.hibernate.persistencia.hibernate.VendaJdbc.incluir(VendaJdbc.java:69)
	at br.com.caelum.hibernate.testeVenda.main(testeVenda.java:53)
Caused by: org.firebirdsql.jdbc.FBSQLException: GDS Exception. 335544665. violation of PRIMARY or UNIQUE KEY constraint "INTEG_104" on table "ITEMVENDA"
	at org.firebirdsql.jdbc.AbstractPreparedStatement.internalExecute(AbstractPreparedStatement.java:730)
	at org.firebirdsql.jdbc.AbstractPreparedStatement.executeUpdate(AbstractPreparedStatement.java:190)
	at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:46)
	at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1168)
	... 11 more

Alguem sabe porque? Como solucionar este problema??

Att. Jonas

Voce está usando um sequence o @Id de itemVenda?

Posta suas classes e o código

@id

@Entity
@Table(name="ItemVenda")
public class ItemVenda implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@Id
	@SequenceGenerator(name = "codigo", sequenceName = "GNT_ITEM_VENDA", allocationSize = 1) 
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "codigo")
	@Basic(optional = false)
	@Column(name = "codigo")
	private int codigo;
	
	@OneToOne(cascade = CascadeType.ALL)  
	@JoinColumn(name = "cd_produto", referencedColumnName="codigo")  
	@Fetch(FetchMode.JOIN)
	@Cascade(org.hibernate.annotations.CascadeType.ALL)
	Produto produto;
	
	@ManyToOne(cascade = CascadeType.ALL)
	@JoinColumn(name = "cd_venda", referencedColumnName="codigo")
	@Fetch(FetchMode.JOIN)
	@Cascade(org.hibernate.annotations.CascadeType.ALL)
	Venda venda;
	
	public int getCodigo() {
		return codigo;
	}
	public void setCodigo(int codigo) {
		this.codigo = codigo;
	}
	public Produto getProduto() {
		return produto;
	}
	public void setProduto(Produto produto) {
		this.produto = produto;
	}
	public Venda getVenda() {
		return venda;
	}
	public void setVenda(Venda venda) {
		this.venda = venda;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + codigo;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final ItemVenda other = (ItemVenda) obj;
		if (codigo != other.codigo)
			return false;
		return true;
	}

}
@Entity
@Table(name="Venda")
public class Venda implements Serializable{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	
	@Id
	@SequenceGenerator(name = "codigo", sequenceName = "GNT_VENDA", allocationSize = 1) 
	@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "codigo")
	@Basic(optional = false)
	@Column(name = "codigo")
	private int codigo;
	
	@Basic(optional = true)
	@Column(name = "nome", length=50)
	private String nome;
	
	@Temporal(TemporalType.DATE)
	@Column(name = "dt_venda")
	private Calendar dataVenda;
	
	@OneToMany(cascade=CascadeType.ALL)
	@JoinColumn(name="codigo")
	private List<ItemVenda> listaItemVenda;
	
	public List<ItemVenda> getListaItemVenda() {
		return listaItemVenda;
	}
	public void setListaItemVenda(List<ItemVenda> listaItemVenda) {
		this.listaItemVenda = listaItemVenda;
	}
	public int getCodigo() {
		return codigo;
	}
	public void setCodigo(int codigo) {
		this.codigo = codigo;
	}
	public String getNome() {
		return nome;
	}
	public void setNome(String nome) {
		this.nome = nome;
	}
	public Calendar getDataVenda() {
		return dataVenda;
	}
	public void setDataVenda(Calendar dataVenda) {
		this.dataVenda = dataVenda;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + codigo;
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		final Venda other = (Venda) obj;
		if (codigo != other.codigo)
			return false;
		return true;
	}

	public int compareTo(Venda o) {
		if(this.getNome().compareTo(o.getNome()) < 0) 
			return -1 ; 
		if(this.getNome().compareTo(o.getNome()) > 0) 
			return 1; 
		return 0; 
	}

	public String toString() {
		return nome;
	}

	
}
public class testeVenda {
	public static void main(String[] args) {
		
		Produto p = new Produto();
		p.setNome("acucar");
		p.setPreco(new BigDecimal(3));
		p.setQuantidade(1);
		
		ProdutoJdbc pJbc = new ProdutoJdbc();

		try {
				pJbc.incluir(p);
			} catch (ExcessaoDAO e) {
				e.printStackTrace();
		}
		
		
		Venda v = new Venda();

		Calendar calendar = Calendar.getInstance();
		calendar.getTime();
		v.setDataVenda(calendar);
		v.setNome("pedro");
		
		List<ItemVenda> listItemVenda = new ArrayList<ItemVenda>();
		ItemVenda iv = new ItemVenda();
		iv.setProduto(p);
		iv.setVenda(v);
		listItemVenda.add(iv);
		
		v.setListaItemVenda(listItemVenda);
		
		VendaJdbc vj = new VendaJdbc();
		try {
			vj.incluir(v);
		} catch (ExcessaoDAO e) {
			e.printStackTrace();
		}
	
	}
}

Troca isso:

    @OneToMany(cascade=CascadeType.ALL)  
    @JoinColumn(name="codigo")  
    private List<ItemVenda> listaItemVenda;  

por

    @OneToMany(cascade=CascadeType.ALL, mappedBy="produto")  
    private List<ItemVenda> listaItemVenda; 

evite anotações nos FIELDS, use elas nos métodos =x … isso vai te ajudar quando vc precisar fazer tratamento dos inputs ou outputs

Nao resolveu hehe

[quote=Lavieri]evite anotações nos FIELDS, use elas nos métodos =x … isso vai te ajudar quando vc precisar fazer tratamento dos inputs ou outputs

[/quote]

Quais tratamentos Lavieri??

Veja no banco… se produto ou venda… tem um unique key… em itemvenda…

Veja a constraint INTEG_104… o que ela diz

[quote=rogelgarcia][quote=Lavieri]evite anotações nos FIELDS, use elas nos métodos =x … isso vai te ajudar quando vc precisar fazer tratamento dos inputs ou outputs

[/quote]

Quais tratamentos Lavieri??[/quote]

por exemplo

[code]@Entity
public class Produto {
private Long id;
private BigDecimal valor;
private String descricao;
private String nome;
@Id @GeneratedValue
public getId() {…}
//…
public BigDecimal getValor() {return valor}
public void setValor(BigDecimal valor) { //#1
this.valor = valor.equals(BigDecimal.ZERO) ? null : valor;
}

   public String getNome() {return nome;}
   public void setNome(String nome) { //#2
        this.nome = nome == null || nome.trim().isEmpty() ? null : nome.trim();
   }

}[/code]

#1 aqui eu estou supondo, que no banco pode existir Produtos legados, sem valor, onde tem o valor ZERO, na verdade era para o campo estar NULL pois esse valor nao e’ definido.

#2 aqui eu estou supondo que no banco, podem existir valores em branco, quando deveriam estar nulos.

O Hiberante usara o metodo SET quando as anotacoes forem nos metodos, o que e’ melhor do que nos FIELDS, pois nos setters / getters vc consegue fazer tratamento na entrada ou na saida dos resutlados…

vc pode ate criar propriedades sem mesmo ter um FIELD para elas no objeto, por exemplo

@Entity
public void Brinde {

       public Integer getQuantidadeTickets() {return quantidadeTickets;}
       //...
       public boolean isGratis() {
            return getQuantidadeTickets() != null && getQuantidadeTickets().equals(0);
       }
       /**
         * Nao use para setar setGratis(false), isso e' ajustado automaticamente apos alterar a quantidade de tickets necessarias
         * para levar esse brinde. Pode ser usado para setGratis(true), o que altera automaticamente a quantidade de tickets para zero.
         * @deprecated usado apenas pela unidade de persistencia
         */
       @Deprecated
       protected void setGratis(Boolean gratis) {
            if (gratis != null && gratis)
                setQuantidadeTickets(0);
       }
}

enfim essas sao apenas duas possibilidades, o fato e’ que com as anotacoes nos metodos, vc pode tratar dados vindo do banco, e nao vai ter seus objetos estuprados heheh injetando valores em suas propriedades privadas =x

nao resolveu, pq ele colocou o campo errado

//errado @OneToMany(cascade=CascadeType.ALL, mappedBy="produto") private List&lt;ItemVenda&gt; listaItemVenda;

//correto @OneToMany(cascade=CascadeType.ALL, mappedBy="venda") private List&lt;ItemVenda&gt; listaItemVenda;

o relacionamento Venda -> ItemVenda
e’ dado pela propriedade “venda” do objeto ItemVenda

Pessoal, eu descobri… só que ainda não sei como solucionar.

O problema de violação é porque ele ta criando uma FK no ItemVenda onde não deve existir.
ta criando uma FK no meu @id que é meu generator… e por isso está dando violação de chave primária!!

alguem sabe porque? como resolver?

Att. Jonas

[quote=TheKill]Pessoal, eu descobri… só que ainda não sei como solucionar.

O problema de violação é porque ele ta criando uma FK no ItemVenda onde não deve existir.
ta criando uma FK no meu @id que é meu generator… e por isso está dando violação de chave primária!!

alguem sabe porque? como resolver?

Att. Jonas[/quote]

coloca o mappedby que ele para de colocar a fk la

essa questao eu resolvi… agora o problema é outro… pode ajudar?

seguinte: sessao de update =/
estou tentando atualizar meus itens venda, mas qndo executo ele simplesmente gera um novo ID no item_venda com atributos null!!
ou seja eu mando atualizar o item venda de iD 2 e ele gera um novo ID com valor null !!!

Venda v = new Venda();

		Calendar calendar = Calendar.getInstance();
		calendar.getTime();
		v.setDataVenda(calendar);
		v.setNome("pedro");
		v.setCodigo(1);
		
		List&lt;ItemVenda&gt; listItemVenda = new ArrayList&lt;ItemVenda&gt;();
		ItemVenda iv = new ItemVenda();;
		Produto p = new Produto();
		p.setNome("petroleo");
		p.setPreco(new BigDecimal(79));
		p.setQuantidade(5);
		p.setCodigo(1);
		listItemVenda.add(iv);

v.setListaItemVenda(listItemVenda);
		
		VendaJdbc vj = new VendaJdbc();
		try {
			vj.alterar(v);
		} catch (ExcessaoDAO e) {
			e.printStackTrace();
		}

Lavieri mas quando vc anota o field… o hibernate nao continua usando o setter nao???

Uma pergunta para os usuarios de Hibernate,

Uma situação que está me deixando com dúvidas:

Tenho uma venda, onde foi efetuado 3 produtos vendidos!
Agora em um update estou atualizando 1 produto, mantendo o 2 produto normal, e quero deletar o 3 produto.

Porem quando efetuei meu update, notei que ele apenas atualiza o item que está para ser alterado… já o resto ele nao faz nada!!!
Isto é normal? O update nao faz delete dos elementos Itens Vendidos que não foram mechidos no update?

Att. Jonas

nao!

ele faz por reflexao, acessa os campos diretamente, seta acessible como true, e invade o campo que era pra ser private setando seu valor, e portanto pode alterar o estado do objeto de uma forma nao esperada…

[quote=TheKill]Uma pergunta para os usuarios de Hibernate,

Uma situação que está me deixando com dúvidas:

Tenho uma venda, onde foi efetuado 3 produtos vendidos!
Agora em um update estou atualizando 1 produto, mantendo o 2 produto normal, e quero deletar o 3 produto.

Porem quando efetuei meu update, notei que ele apenas atualiza o item que está para ser alterado… já o resto ele nao faz nada!!!
Isto é normal? O update nao faz delete dos elementos Itens Vendidos que não foram mechidos no update?

Att. Jonas[/quote]

try it

venda = session.load(Venda.class,id); venda.getItensVendidos().remove(3);

o hiberante nao atualiza nao o relacionamento