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

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.

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

c ficar com duvia avisa

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.

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;
//...
}

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

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

[/quote]

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 ^^

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).

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

[code]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;

//…
}[/code]

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

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?

[quote=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?

[/quote]

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

Ok. Vou testar aqui.

No mais obrigado pela ajuda, esclareceu bastante.

[quote=geidivan]Ok. Vou testar aqui.

No mais obrigado pela ajuda, esclareceu bastante.[/quote]

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

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?

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…

Certo, entendi.

Valeu cara.