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

Bom já tentei de tudo. Procurei um relacionamento parecido, até achei mas não gera tabela. Então não sei se tem alguma coisa errada ou se está tudo errado hehehe.
Vou postar o relacionamento e o resultado. Se alguém souber porque ele está gerando a coluna ITENS_ID com o valor do ID do Pedido eu agradeço muito.

Pedido.java

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(nullable=false)
private Set<ItemPedido> itens= new HashSet<ItemPedido>();

ItemPedido.java

@EmbeddedId
private ItemPedidoPK id;
@Column(nullable=false)
private Integer quantidade;

ItemPedidoPK.java

@ManyToOne(fetch=FetchType.LAZY) //Muitos Itens para um pedido...?!?
@JoinColumn(updatable=false,insertable=false)
public Pedido pedido;
@OneToOne(fetch=FetchType.LAZY) //Um produto para um item de produto...?!?
@JoinColumn(updatable=false,insertable=false)
public Produto produto;

Esta gerando a tabela ItemPedido dessa forma.

PKTABLE_NAME....PKCOLUMN_NAME.....FKTABLE_NAME.....FKCOLUMN_NAME....KEY_SEQ.
PEDIDO..........ID................ITEMPEDIDO.......PEDIDO_ID........1.
PEDIDO..........ID................ITEMPEDIDO.......ITENS_ID.........1.
PRODUTO.........ID................ITEMPEDIDO.......PRODUTO_ID.......1.	

COLUMN_NAME....TYPE_NAME
QUANTIDADE.....INTEGER
PRODUTO_ID.....BIGINT
PEDIDO_ID......BIGINT
ITENS_ID.......BIGINT

esta gerando assim pq vc mapeou assim ^^ para mapear de um lado e aproveitar a mesma coluna no outro objeto é preciso usar mappedBy

Evite sempre que possivel chaves compostas, se o seu banco é legado, e vc não tem opção paciencia, caso contrario prefira um id proprio na classe itempedido, com valores auto-incremento, e ponho uma constraint unique em pedido, produto…

mas a melhor forma de mapear este seu caso, fazendo o uso da chave composta, seria assim

@Entity public class Pedido { //... OneToMany(cascade=CascadeType.ALL, mappedBy="pedido") //adicionando o mappedBy @JoinColumn(nullable=false) private Set<ItemPedido> itens= new HashSet<ItemPedido>(); //... }

[code]@Entity
@IdClass(ItemPedidoPK.class) //adicioando @IdClass para a chave composta
public class ItemPedido {
@Id //adicionando o @Id e colocado dentro de ItemPedido
@ManyToOne(fetch=FetchType.LAZY)
// @JoinColumn(updatable=false,insertable=false) um Id não pode ser insertable = false
public Pedido pedido;

@Id //adicionando o @Id e colocado dentro de ItemPedido
@OneToOne(fetch=FetchType.LAZY)
// @JoinColumn(updatable=false,insertable=false) um Id não pode ser insertable = false
public Produto produto;

@Column(nullable=false)
private Integer quantidade;
}[/code]

ItemPedidoPk permanece igual esta…

e aí MVA ?? funcionou cara ?? dá um retorno aí pra sabermos…

Falows :wink:

[EDIT] Não tinha visto que a resposta era recente… Mals Aê…

valew Lavieri, mas como estava com pressa, acabei apelando para o Netbeans e mandei ele montar o relacionamento com base no banco de dados.
Funcionou, mas ele mapeou de outra forma. Eu particularmente não gostei porque ele colou apenas o id da tabela pedido e produto na classe ItemPedidoPK. E mapeou o Objeto Produto e Pedido na classe ItemPedido. O que notei que não tinha no relacionamento e que ele criou foi uma lista (Set) de ItemPedido na classe Produto, isso eu não queria. Agora está funcionando, mas vou tentar usar o seu relacionamento.

Produto.java

@OneToMany(cascade = CascadeType.ALL, mappedBy = "produto", fetch = FetchType.LAZY)
private Set<ItemPedido> itemPedido;

Pedido.java

@OneToMany(cascade = CascadeType.ALL, mappedBy = "pedido", fetch = FetchType.LAZY)
private Set<ItemPedido> itens;

ItemPedido.java

@EmbeddedId
protected ItemPedidoPK itemPedidoPK;
    
@Basic(optional = false)
@Column(name = "QUANTIDADE")
private int quantidade;
    
@JoinColumn(name = "PEDIDO_ID", referencedColumnName = "ID", insertable = false, updatable = false)
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private Pedido pedido;
    
@JoinColumn(name = "PRODUTO_ID", referencedColumnName = "ID", insertable = false, updatable = false)
@ManyToOne(optional = false, fetch = FetchType.LAZY)
private Produto produto;

ItemPedidoPK

@Basic(optional = false)
@Column(name = "PRODUTO_ID")
private long produtoId;
@Basic(optional = false)
@Column(name = "PEDIDO_ID")
private long pedidoId;

Assim está funcionando, mas to achando muito burocrático. Vou tentar usar o seu mapeamento e posto o resultado. Quanto a usar Chave composta, eu já sabia disso, mas esse é um exemplo clássico que gera briga com a maioria dos DBA’s. Segundo eles a chave única nesses casos é desperdício.

Não cheguei a testar o relacionamento, mas o editor acusa o seguinte erro na Classe Produto:
“Attribute named “pedido” has invalid mapping for this relationship”.
Foi exatamente isso que me fez desistir de usar @IdClass(ItemPedidoPK.class).

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]