Hibernate annotations - Composite-id com chave estrangeira, tem como?

14 respostas
geidivan

Pessoal,

Tenho um mapeamento de uma classe que possui uma chave composta, porém um dos itens dessa chave é também uma chave estrangeira. Como faço isso? Tentei o seguinte:

@Entity
@Table(name="item_carga_venda", schema="cdpc")
public class ItemCargaVenda implements Serializable {

	private static final long serialVersionUID = 1L;
	
	@EmbeddedId
	private ItemCargaVendaPK id;	
	@Column(name="qtd_volumes")
	private int qtd_volumes;
	@Column(name="cod_situacao")
	private String cod_situacao;
  
       // getters and setters ...
}

A chave composta:

@Embeddable
public class ItemCargaVendaPK implements Serializable {

	private static final long serialVersionUID = 1L;

	@Column(name="num_pedido")
	private int num_pedido;
	@Column(name="num_item")
	private int num_item;
	
	// RELACIONAMENTOS 
       @ManyToOne(fetch = FetchType.EAGER)
       @JoinColumn(name="num_carga_venda")
       @Fetch(FetchMode.JOIN)
       private CargaVenda carga;

       // getters and setters ...

}

É assim mesmo? Na classe CargaVenda eu faço um relacionamento para essa ItemCargaVendaPK?

Tô apanhando demais para o hibernate com essas chaves compostas. Há, quero fazer do modo certo mesmo. Nada disso de criar uma coluna com uma chave primária. A intenção é fazer o mapeamento correto.

14 Respostas

Lavieri

da uma olhada aqui… http://www.guj.com.br/posts/list/121523.java

c ficar com duvia avisa

geidivan

Já havia visto este tópico, mas não ajudou muito.

No caso dele, ele tem uma chave composta e uma chave estrangeira separada. No meu caso, eu preciso que a chave estrangeira também faça parte da chave primária.

Lavieri

como não ??

a chave composta contem 2 chaves estrageiras Loja e EstoqueProduto

EDIT: talvez o que vc keira é como mapear a parte da chave composta ? que é estrangeira ?? segue mapeamento abaixo

@Entity
@Table(name = "estoque_produto_loja")
public class EstoqueProdutoLoja implements Serializable {
    @EmbeddedId
    protected EstoqueProdutoLojaPK estoqueProdutoLojaPK;
//...
    @OneToMany(cascade = CascadeType.ALL, mappedBy = "estoqueProdutoLoja")   
    private Set<EventoEstoqueMinimo> eventoEstoqueMinimoCollection;   
//...
    @JoinColumn(name = "estoque_produto_id", referencedColumnName = "id", insertable = false, updatable = false)
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private EstoqueProduto estoqueProduto;

    @JoinColumn(name = "loja_id", referencedColumnName = "id", insertable = false, updatable = false)
    @ManyToOne(optional = false, fetch = FetchType.LAZY)
    private Loja loja;
//...
}
geidivan

Mas esses relacionamentos não estão dentro da classe EstoqueProdutoLojaPK. Eles farão parte da chave primária?

Lavieri

geidivan:
Mas esses relacionamentos não estão dentro da classe EstoqueProdutoLojaPK. Eles farão parte da chave primária?

sim! estão fora… dentro de EstoqueProdutoLoja… pq não há motivos de colocar ele dentro de EstoqueProdutoLojaPk

eles são relacionamentos da tabela EstoqueProdutoLoja, e não da chave…

a chave é apenas uma composição de varios campos… o relacionamento é da tabela…

Vc quer colocar o relacionamento dentro da PK por que ?? … c realmente quiser, talvez de certo, esde que vc explicite que insertable e updatable são false, mas não vejo motivos pra por dentro da PK

C sua duvida for no mapeamento de Loja e de EstoqueProduto pode falar, que tento elucidar mostrando o mapeamento delas… mas o relacionamento como fiz, funciona ^^

geidivan

Deixa eu explicar o que tenho aqui.

Na tabela item_carga tenho a seguinte chave composta: num_item, num_pedido, num_carga.

Sendo que num_carga é uma chave estrangeira da tabela carga.

Com num_item e num_pedido dentro do PK e o num_carga fora pode ocorrer a seguinte situação:

num_item num_pedido num_carga
1 123 555
1 123 444

Ou seja, como num_carga está fora do PK, pode haver a mesma combinacao item+pedido para cargas diferentes, mas isso não pode acontecer. Quero que a combinação item+pedido só ocorra para um única carga. Por isso preciso colocar a chave estrangeira como parte da chave primária entende?

É como seu estivesse transportando o mesmo item do mesmo pedido em caminhões diferentes, mas isso é impossivel (só se eu clonar ele, rsrs).

Lavieri

vc não entendeu como ta a minha chave composta...

@Embeddable   
public class EstoqueProdutoLojaPK implements Serializable {   
    @Basic(optional = false)   
    @Column(name = "estoque_produto_id")   
    private int estoqueProdutoId;   
    @Basic(optional = false)   
    @Column(name = "loja_id")   
    private int lojaId;   
//...
}

como vc pode ver... em EstoqueProdutoLojaPK existe a referencia aos IDs, porem não a referencia ao objeto Loja e ao objeto EstoqueProduto

mais no objeto EstoqueProdutoLoja existe referencia ao objeto Loja e ao objeto EstoqueProduto
isso se da pq o relacionamento é com EstoqueProdutoLoja e não com a chave composta (EstoqueProdutoLojaPK) ... entendeu ??

ai para resolver isso... o objeto Loja e a objeto EstoqueProduto de EstoqueProdutoLoja são setados como insertable e updatable false...
ou seja, não são eles que vão pra tabela e sim suas referencias de ID contidos dentro do PK ...

o que estou te falando, é que vc não precisa por a referencia do Objeto relacionando dentro do PK, vc deve fazer isso fora, dentro do objeto fica apenas o ID ...

no seu caso seria assim...

public class ItemCargaPK implements Serializable {
   @Basic(optional = false)   
   @Column(name = "num_item")
   private Integer ItemId;
   @Basic(optional = false)   
   @Column(name = "num_pedido")
   private Integer PedidoId;
   @Basic(optional = false)   
   @Column(name = "num_carga")
   private Integer CargaId;
//....
}
ai a sua classe ItemCarga seria assim
public class ItemCarga implements Serializable {   
    @EmbeddedId   
    protected ItemCargaPK itemCargaPK ; 

    //Conciderando que na tabela Carga o campo relacionando s echame "id"
    @JoinColumn(name = "num_carga", referencedColumnName = "id", insertable = false, updatable = false)   
    @ManyToOne(optional = false, fetch = FetchType.LAZY)   
    private Carga carga;
//...
}

... posta ai depois falando se entendeu e c deu certo, ou c ainda tem duvidas

geidivan

Agora entendi, dentro da PK você declara o num_carga como um Column comum e fora faz o relacionamento.

Com esse insertable e updatable false, quando eu mandar salvar um objeto desse EstoqueProdutoLoja eu só seto a classe do relacionamento e deixo os campos do PK em branco que ele insere sozinho?

Lavieri

geidivan:
Agora entendi, dentro da PK você declara o num_carga como um Column comum e fora faz o relacionamento.

Com esse insertable e updatable false, quando eu mandar salvar um objeto desse EstoqueProdutoLoja eu só seto a classe do relacionamento e deixo os campos do PK em branco que ele insere sozinho?

não faz sozinho não… como falei, não é Insertable e Updatable… se quiser que ele propague quando atualizar… basta declarar algo assim na sua classe ItemCarga

public void setCarga(Carga carga) { this.itemCargaPK.setNumCarga(carga.getId()); this.carga = carga; }
Ps.: é bom checar antes de itemCargaPk é null, para não gerar nullPointerException

geidivan

Ok. Vou testar aqui.

No mais obrigado pela ajuda, esclareceu bastante.

Lavieri

geidivan:
Ok. Vou testar aqui.

No mais obrigado pela ajuda, esclareceu bastante.

so pra esclarecer, ele não faz sozinho set… porem o Hibernate faz o get via LAZY quando entidade é persistente… ou seja…

c vc carregar um dado do banco de dados… ele vai carregar tudo… e vai continuar null a Carga…

porem quando vc fizer… getCarga() … o hibernate vai dar refresh no objeto Carga … ^^

porem no setCarga, nada é realizado, por isso não muda nada no ID

geidivan

Eu falo o seguinte:

Na PK eu faço:

ItemCargaVenda.getId.setNum_carga(123);

No relacionamento eu faço:

ItemCargaVenda.getCarga.setNum_carga(123);

Quando eu mandar inserir esse objeto itemCargaVenda no banco ele só vai preencher a coluna uma vez certo? Eu devo fazer o set na coluna do PK, na classe do relacionamento ou tanto faz?

Lavieri

O dieal é que vc faça algo como

digamos que seu

  • item seja o 9
  • pedido seja o 12
  • e a carga 29

itemCargaVenda.setItemCargaVendaPk(new ItemCargaVendaPk(9,12,29));

não vejo motivos pra vc cahmar o IdPK e ficar setando seus valores…

id é feito uma vez, não é alterado, então não tem nem motivos de ter sets…

geidivan

Certo, entendi.

Valeu cara.

Criado 23 de março de 2009
Ultima resposta 23 de mar. de 2009
Respostas 14
Participantes 2