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>();
@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 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;
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.
@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).
é 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:
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…
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.
[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;
//...
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. 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.