JPA gerando Tabela com uma coluna a mais...(Resolvido)

deixa ele relcamar =x

é pq ele não enxerga realacionamentos 1-N ou 1-1 em objetos embutidos, pois o objeto embutido não mostra o escopo do objeto completo… pode testar mesmo com o aviso do compilador

Cara funcionou. Mas sem o @JoinColumn no Pedido. Se colocar isso ele cria a coluna a mais. Na verdade esse parece ser o problema todo, colocou isso ele enfia uma coluna na tabela. Eu consegui fazer do jeito que eu queria, evitando deixar Produto e Pedido na classe ItemPedido. Assim mantenho eles somente na classe PK. Acredito que acaba dando na mesma, mas foi legal ver as opções para chave composta. Nessa brincadeira acabei aprendendo as 3 formas. Valew mesmo a ajuda. Abaixo segue como ficou as classes.

Para o seu exemplo funcionar redondo o Pedido deve ficar sem o @JoinColumn:

   @Entity  
   public class Pedido {  
      //...  
      OneToMany(cascade=CascadeType.ALL, mappedBy="pedido", fetch = FetchType.LAZY))
      private Set<ItemPedido> itens= new HashSet<ItemPedido>();  
      //...  
   }  

Abaixo a maneira que consegui fazer funcionar do jeito que eu tinha pensado inicialmente. Observe o mappedBy.

   @Entity  
   public class Pedido {  
      //...  
      @OneToMany(cascade = CascadeType.ALL, mappedBy = "id.pedido", fetch = FetchType.LAZY)
      private Set<ItemPedido> itens= new HashSet<ItemPedido>();  
      //...  
   }  
@Entity
public class ItemPedido{
     @EmbeddedId
     public ItemPedidoPK id;
	
     @Column(nullable=false)
     private int quantidade;
     //...
}
@Embeddable
public final class ItemPedidoPK{
    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(updatable=false,insertable=false)  
    public Pedido pedido;
   
    @OneToOne(fetch=FetchType.LAZY)
    @JoinColumn(updatable=false,insertable=false)  
    public Produto produto;
}

Funciona, mas o editor acusa erro de mapeamento pra todo lado. :lol:

sim sim… é sem o joincolum, esqueci de retirar isso, quando dei ctrl+c, ctrl+v…

esse é o problema quando vc diz, joincolum, vc esta especificando que este lado é o proprietario do relacionamento, então se vc iver 2 joincolums, um em cada lado, ele cria uma coluna em cada lado… é pr aisso que existe o mappedBy, para o lado que não é o proprietario.

Sobre vc não querer colocar o objeto dentro de itempedido, é uma escolha sua… mas vai achar pior quando for fazer as queries.

Quem tem o produto é o ItemPedido, e não o id do itempedio… colocar isso dentro do Id distorce o sentido, e fica pior de manter, e de montar querys.

de toda forma, como vc esta fazendo um banco novo, se fosse vc ignorava o dba, e fazi a chave primaria

Então, na verdade só postei porque consegui fazer da maneira que pensei inicialmente. Inclusive foi a forma que vi em alguns exemplos na internet. Mas sem duvida não é a melhor abordagem, já que do ponto de vista OO não deveria existir ClassePK, postei porque consegui e sabia que funcionava, só não estava conseguindo fazer funcionar.
Eu acabei optando pela forma como o NetBeans gerou. Não é a que mais me agrada, mas é um misto dessas duas soluções e é a que mais se parece com o apresentado no Tutorial da Sun. E o mais importante…nem o editor do eclipse nem o Hibernate Tools “xiam”. As outras duas abordagem geram erros nessa duas ferramentas. O importante mesmo é o que eu aprendi com isso.
Quanto ao DBA não se pode ignorar o cara que aprova o modelo. Infelizmente tem DBA que aceita e DBA que não aceita. Mas tem soluções para os dois casos hehehe. Valew mesmo a ajuda. :thumbup:

chave composta é uma tristesa… principalmente na hora de fazer relacionamentos… =/

mas vc esta usando IdClass ?? pq com IdClass pelomenos fica mais OO

Com IdClass fica mais OO, mas o editor e o hibernate tools reclama. Uso o hibernate tools para algumas coisas então paciência.

eu gosto mais do JPA do eclipse galileo, é muito bom ^ ^ … mas é assim mesmo…

cola aqui como vc mapeou com o EmbeddedId

eu gosto mais do JPA do eclipse galileo, é muito bom ^ ^ … mas é assim mesmo…

cola aqui como vc mapeou com o EmbeddedId[/quote]

Não entendi de qual EmbeddedId você se refere. O código que estou utilizando atualmente eu postei la em cima. É o que o NetBeans montou. Se está falando da sua solução eu fiz exatamente como vc postou, mas da quele aviso do mappedBy, e quem reclama é o Editor do eclipse, creio que seja o JPA do Galileo. O Problema no Hibernate Tools é quando ele tenta montar a configuração. Da um erro maluco. Uso ele para montar as querys JPA e ver como ficam no SQL. O JPA do Galileo faz isso? Não achei essa funcionalidade nele.

eu gosto mais do JPA do eclipse galileo, é muito bom ^ ^ … mas é assim mesmo…

cola aqui como vc mapeou com o EmbeddedId[/quote]

Não entendi de qual EmbeddedId você se refere. O código que estou utilizando atualmente eu postei la em cima. É o que o NetBeans montou. Se está falando da sua solução eu fiz exatamente como vc postou, mas da quele aviso do mappedBy, e quem reclama é o Editor do eclipse, creio que seja o JPA do Galileo. O Problema no Hibernate Tools é quando ele tenta montar a configuração. Da um erro maluco. Uso ele para montar as querys JPA e ver como ficam no SQL. O JPA do Galileo faz isso? Não achei essa funcionalidade nele.[/quote]

então na configuração que vc mostrou vc esta usando EmbeddedId … mas vc já tentou usar ?? tenho uma impressão que não vai funcionar… apesar de não estar enxergando erros no meu mapeamento…

uma chave não pode ter seus campos com insertable e updetable false… ja tentou persitir algum objeto ?? pra ver o resultado ??

esse mapeamento…

[code]# @Embeddable
public final class ItemPedidoPK{
@ManyToOne(fetch=FetchType.LAZY)
@JoinColumn(updatable=false,insertable=false)
public Pedido pedido;

 @OneToOne(fetch=FetchType.LAZY)  
 @JoinColumn(updatable=false,insertable=false)    
 public Produto produto;  

} [/code]

não vai dar muito certo… e da mesma forma que vc usou assim com EmbedableId na sua classe ItemPedido poderia ter usado com IdClass…

a solução que te passei sem os insertables e updetable false geram problemas segundo o avaliador, mas porem podem ser persistida…

tenta persitir um objeto e me fala o resultado…

O que acontece é o seguinte: Tanto com IdClass quanto com EmbeddedId (Produto e Pedido dentro da ItemPedidoPK) o comportamento é o mesmo. Ao tentar persistir Pedido com tudo setado, o seu hashCode() é acessado e como seu id que é um Long não foi setado ele da NullPointerException. Dai mudei o id para long primitivo e da esse erro: [color=red]object references an unsaved transient instance - save the transient instance before flushing: Pedido[/color].
As duas formas funcionam se o pedido for salvo antes de ser setado no ItemPedido. Eu entendi o que vc quis dizer, mas é estranho. Parece que ele tenta persistir primeiro ItemPedido ao invés de persistir o Pedido. Isso nos 2 casos, com ou sem insertable e updatable = false. Mas Foi o NetBeans que montou dessa forma, mesmo usando ItemPedidoPK com primitivos.
Aliás faz sentido não serem insertable e updatable. O Item do pedido só pode ser salvo se já existir um pedido. Acho que é por isso que monta dessa forma.

ele montou assim pq ele supos uma sobrecarga…

pro netbeans o correto seria

[code]@Embeddable
public final class ItemPedidoPK{
@Column(name="nome_do_campo") //se não me engano name=pedido_id
public Integer pedidoId;
@Column(name="nome_do_campo") //se não me engano name=produto_id
public Integer produtoId;

  @ManyToOne(fetch=FetchType.LAZY)    
  @JoinColumn(updatable=false,insertable=false)      
  public Pedido pedido;    
     
  @OneToOne(fetch=FetchType.LAZY)    
  @JoinColumn(updatable=false,insertable=false)      
  public Produto produto;    

} [/code]

é isso que o hibernate esparava que vc fizesse… para ele poder persitir via pedidoId e produtoId …
vc vai rodar muito… mas ele não vai entender que é possivel ter relacionamentos 1-1 ou n-1 em itens @Embedabble

vc acaba no final, tendo que se preucupar com quem persiste onde…

eu anotaria assim

[code]@Embeddable
public final class ItemPedidoPK implements Serializable {
@ManyToOne(fetch=FetchType.LAZY)
//talvez, e só talvez, vc usando @IdClass vc possa manter as antigas anotações @JoinColum(insertable e updatable = false)
public Pedido pedido;

  @OneToOne(fetch=FetchType.LAZY) //<== eu axo que aki tb é @ManyToOne
  public Produto produto;    

  //vc aqui é obrigaod a implementar equals e hashcode()

} [/code]

@Entity public class Pedido { //... @OneToMany(cascade = CascadeType.ALL, mappedBy = "pedido", fetch = FetchType.LAZY) private Set<ItemPedido> itens= new HashSet<ItemPedido>(); //... }

[code]@Entity
@IdClass(ItemPedidoPK.class)
public class ItemPedido {

  @Id
  @ManyToOne(fetch=FetchType.LAZY)
  public Pedido pedido;    

  @Id
  @OneToOne(fetch=FetchType.LAZY) //<== eu axo que aki tb é @ManyToOne
  public Produto produto;    

  @Column(nullable=false)  
  private int quantidade;  
  //...  

} [/code]

me adiciona no gtalk! que nois conversa… o meu gmail ta na mensagem privada q te enviei…

to quase abrindo um projeto no eclipse pra testar esse relacionamento hehehe

Cara to te falando. Não faz diferença usar IdClass ou EmbedebleId. Tem que persistir o Pedido primeiro nos dois casos por causa do hashCode(). Ainda por cima com IdClass o Hibernate Tools não funciona e o projeto fica mostrando erro. :expressionless: E realmente o Netbeans mapeou Produto como ManyToOne. Não sei se é possivel persistir tudo de uma vez. Se for, talvez não role com chave composta.

hashCode não tem nada a ver com a parada… c seu hash ta bugando ai é outro problema… o hash é pra ele testar igualdade…

a geração do código ID tem q propagar… seu problema é esse insertable false e updatable false… veja aki meu teste

[code] s.beginTransaction();

	Produto bolo = (Produto) s.load(Produto.class, 1);
	Produto suco = (Produto) s.load(Produto.class, 2);
	
	
	Pedido p = new Pedido();
	
	p.getItens().add(new ItemPedido(p,bolo,3));
	p.getItens().add(new ItemPedido(p,suco,7));
	
	s.save(p);
	s.getTransaction().commit();[/code]

funcinou perfeito aki

Apenas para confirmar…

[code] List<Pedido> pedidos = s.createCriteria(Pedido.class).list();

	for(Pedido pedido : pedidos) {
		System.out.println("Pedido id: " + pedido.getId());
		for(ItemPedido i : pedido.getItens()) {
			System.out.println("produto = " +i.getProduto() + " no pedido " + i.getPedido() + " quantidade = " + i.getQuantidade());
		}
	}[/code]

[quote]produto = bolo no pedido 3 quantidade = 3
produto = suco no pedido 3 quantidade = 7[/quote]

Apenas pra constar uma abordagem melhor é essa

[code] s.beginTransaction();

Produto bolo = (Produto) s.load(Produto.class, 1);
Produto suco = (Produto) s.load(Produto.class, 2);

Pedido p = new Pedido();

p.addItem(bolo,3);
p.addItem(suco,7);

s.save§;
s.getTransaction().commit();[/code]

ai o método addItem seria…

public ItemPedido addItem(Produto produto, int quantidade) { ItemPedido item = new ItemPedido(this,produto,quantidade); getItens().add(item); return item; }

Agora que isolei as classes realmente funcionou. Ia postar mas vc foi mais rápido. Tem alguma coisa errada mesmo com meu hashCode ou a sequencia em que ele é usado. Inclusive funcionou com o Hibernate Tools também. Mas o editor “xia” por causa daquele problema que você falou. Problema resolvido cara. Valew a ajuda e atenção.

outra coisa

field publico é furado… anotação em propriedade é algo melhor, pq vc pode fazer operações nos dados que xegam… vou postar como mapiei aki

[size=18]Produto.java[/size]

[code]package br.com.tomazlavieri.model;

import java.io.Serializable;
import javax.persistence.*;

@Entity
public class Produto implements Serializable {
private static final long serialVersionUID = 306116498256151785L;
private Integer id;
private String nome;

@Id
@GeneratedValue
public Integer getId() {
	return id;
}

public void setId(Integer id) {
	this.id = id;
}

public String getNome() {
	return nome;
}

public void setNome(String nome) {
	this.nome = nome;
}

@Override
public int hashCode() {
	if (getNome() == null)
		return super.hashCode();
	final int prime = 7;
	int result = 1;
	result = prime * result + nome.hashCode();
	return result;
}

@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (getNome() == null)
		return false;
	if (!(obj instanceof Produto))
		return false;
	Produto other = (Produto) obj;
	return getNome().equals(other.getNome());
}

@Override
public String toString() {
	return getNome();
}

}[/code]

[size=18]Pedido.java[/size]

[code]package br.com.tomazlavieri.model;

import java.io.Serializable;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.Set;

import javax.persistence.*;
import static javax.persistence.CascadeType.ALL;
import static javax.persistence.TemporalType.TIMESTAMP;

@Entity
public class Pedido implements Serializable {
private static final long serialVersionUID = -8514647334843363802L;
private Integer id;
private Date data;
private Set<ItemPedido> itens = new HashSet<ItemPedido>();

public Pedido() {
	super();
}
@Id
@GeneratedValue
public Integer getId() {
	return id;
}

public void setId(Integer id) {
	this.id = id;
}

@OneToMany(mappedBy="pedido", cascade = ALL)
protected Set&lt;ItemPedido&gt; getItens() {
	return itens;
}

/**
 * Resgata a lista somente leitura dos pedidos.
 * @return
 */
@Transient
public Set&lt;ItemPedido&gt; getItensRO() {
	return Collections.unmodifiableSet(getItens());
}
/**
 * Adiciona um item ao pedido
 * @param produto
 * @param quantidade
 * @return
 */
@Transient
public ItemPedido addItem(Produto produto, int quantidade) {  
	ItemPedido item = new ItemPedido(this,produto,quantidade);  
	getItens().add(item);  
	return item;  
}
/**
 * Remove um item do pedido
 * @param produto
 * @return
 */
@Transient
public boolean remove(Produto produto) {  
	ItemPedido item = new ItemPedido(this,produto,0);  
	return getItens().remove(item);
}

protected void setItens(Set&lt;ItemPedido&gt; itens) {
	this.itens = itens;
}

@PrePersist
@Transient
public void prePersist() {
	setData(new Date());
}

@Temporal(TIMESTAMP)
@Column(updatable = false)	public Date getData() {
	return data;
}
public void setData(Date data) {
	this.data = data;
}
@Override
public int hashCode() {
	if (getId() == null)
		return super.hashCode();
	final int prime = 11;
	int result = 1;
	result = prime * result + getId().hashCode();
	return result;
}

@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (getId() == null)
		return false;
	if (!(obj instanceof Pedido))
		return false;
	Pedido other = (Pedido) obj;
	return getId().equals(other.getId());
}

@Override
public String toString() {
	return String.valueOf(getId());
}

}[/code]

[size=18]ItemPedido.java[/size]

[code]package br.com.tomazlavieri.model;

import java.io.Serializable;
import javax.persistence.*;

@Entity
@IdClass(ItemPedidoPK.class)
public class ItemPedido implements Serializable {
private static final long serialVersionUID = -7759835629199252623L;
private static final String TO_STRING = “[pedido = %s , produto = %s , quantidade = %d]”;
private Produto produto;
private Pedido pedido;
private Integer quantidade;

public ItemPedido() {
	super();
}
public ItemPedido(Pedido p,Produto produto, int quantidade) {
	setPedido(p);
	setProduto(produto);
	setQuantidade(quantidade);
}
@Id
@ManyToOne
public Produto getProduto() {
	return produto;
}

public void setProduto(Produto produto) {
	this.produto = produto;
}
@Id
@ManyToOne
public Pedido getPedido() {
	return pedido;
}

public void setPedido(Pedido pedido) {
	this.pedido = pedido;
}

public Integer getQuantidade() {
	return quantidade;
}

public void setQuantidade(Integer quantidade) {
	this.quantidade = quantidade;
}

@Override
public int hashCode() {
	if (getProduto() == null || getPedido() == null)
		return super.hashCode();
	final int prime = 13;
	int result = 1;
	result = prime * getPedido().hashCode();
	result = prime * getProduto().hashCode();
	return result;
}

@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (getPedido() == null || getProduto() == null)
		return false;
	if (!(obj instanceof ItemPedido))
		return false;
	ItemPedido other = (ItemPedido) obj;
	return getProduto().equals(other.getProduto()) &&
			getPedido().equals(other.getPedido());
}

@Override
public String toString() {		
	return String.format(TO_STRING, getPedido(),getProduto(),getQuantidade());
}

}[/code]

[size=18]ItemPedidoPK.java[/size]

[code]@Embeddable
public class ItemPedidoPK implements Serializable {
private static final long serialVersionUID = 6958675790304225564L;
private Pedido pedido;
private Produto produto;

public ItemPedidoPK() {
	super();
}

@ManyToOne
public Produto getProduto() {
	return produto;
}

public void setProduto(Produto produto) {
	this.produto = produto;
}

@ManyToOne
public Pedido getPedido() {
	return pedido;
}

public void setPedido(Pedido pedido) {
	this.pedido = pedido;
}

@Override
public int hashCode() {
	if (getProduto() == null || getPedido() == null)
		return super.hashCode();
	final int prime = 17;
	int result = 1;
	result = prime * getPedido().hashCode();
	result = prime * getProduto().hashCode();
	return result;
}

@Override
public boolean equals(Object obj) {
	if (this == obj)
		return true;
	if (getPedido() == null || getProduto() == null)
		return false;
	if (!(obj instanceof ItemPedido))
		return false;
	ItemPedidoPK other = (ItemPedidoPK) obj;
	return getProduto().equals(other.getProduto()) &&
			getPedido().equals(other.getPedido());
}

}[/code]