EJB3 - Chave composta c/ foreign key

12 respostas
G

Alguém teria um exemplo para me indicar de criação de Entity usando chave composta c/ foreign key?

Todos os exemplos que achei foram usando campos simples.

Abraços.

12 Respostas

Joseleine

Olá.. fazer entity com chave composta é simples. :D

Em uma classe, vc coloca só os campos que pertencem à chave composta, à qual vc mapeia como @Embeddable:

public class TestePk implements Serializable {

    private int firstId;
    private int secondId;


//construtor

    @Column(name="FIRST_ID")
    public int getFirstId() {
         return firstId;
    }

    //set normal para fist id


    @Column(name="SECOND_ID")
    public int getSecondId() {
         return secondId;
    }

    //set normal para second id
 

}

Depois cria a entity que será mapeada com a tabela:

@Entity
@Table(name="TABELA_TESTE")
public class Teste implements Serializable {
    
    private TestePk _pk;

   //construtor normal para Teste

    @EmbeddedId
    public TestePk getPk() {
        return pk;
    }

    //set normal para o pk

}

Essa é a única diferença de mapear uma entity com uma chave simples. Os outros campos da tabela, vc adiciona na entity "Teste" normal, como faz com outras entities. Ok?

Espero ter ajudado.

G

Joseleine, obrigado por responder.

Eu já havia visto esse tipo de implementação, mas gostaria de saber exatamente como deve ser feito quando as duas chaves são Foreign Keys.

Exemplo:

  • Tenho 3 tabelas: perfil, funcao e funcao_perfil.

Sendo que as chaves de cada tabela são:

  • perfil: id_perfil
  • funcao: id_funcao
  • funcao_perfil: id_perfil e id_funcao

A tabela funcao_perfil é o resultado do relacionamento muitos pra muitos entre perfil e funcao.

Como ficaria a construção do entity FuncaoPerfil ?

Obrigado.

Joseleine

Aaaaahhhh sim, agora sim vc explicou direitinho… rs…

Bom, quando é assim fazemos da seguinte maneira:

Vc mapeiaria normalmente as entities que correspondem às tabelas que tem só um id, no seu caso perfil e função. A diferença é que na entity perfil vc teria uma lista de “função”, a qual vc mapeia ManyToMany. E em função, vc faz uma lista do tipo “perfil”, mapeando tbm como ManyToMany. Assim:

Na entity Perfil:

@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name="FUNCAO_PERFIL",
        joinColumns={@JoinColumn(name="id_perfil")},   inverseJoinColumns={@JoinColumn(name="id_funcao")})
    public List<Funcao> getFuncoes() {
        return _funcoes;
    }
    
    public void setFuncoes(List<Funcao> funcoes) {
        this._funcoes = funcoes;
    }

E na entity Função:

@ManyToMany(fetch=FetchType.EAGER)
@JoinTable(name="FUNCAO_PERFIL",
        joinColumns={@JoinColumn(name="id_perfil")},   inverseJoinColumns={@JoinColumn(name="id_funcao")})
    public List<Perfil> getPerfis() {
        return _perfis;
    }
    
    public void setPerfis(List<Perfil> perfis) {
        this._perfis = perfis;
    }

A tabela do meio, a que contém o id das duas tabelas não precisa mapear… a JPA faz tudo sozinha… rs… ótimo, não é?

Tente ae, depois me fale se deu certo. Boa sorte.

G

deu certo sim.
Muito obrigado =)

G

Uma outra dúvida…

E no caso deu ter uma tabela cuja chave eh composta por um item dela e uma foreign key?

Exemplo:

Tenho duas tabelas: arquivo e versao_arquivo

As chaves de cada uma são:
arquivo: id_arquivo
versao_arquivo: id_arquivo e versao (ambos tipo inteiro)

Teria que fazer algo parecido com o exemplo inicial do Joseleine, mas usando um campo que é estrangeiro (id_usuario).

Alguém sabe dizer como proceder nesse caso?

Obrigado.

Joseleine

guhreis,

Não entendi de onde surge esse id_usuário que vc colocou no final do post. Acho que sei como te ajudar, mas antes preciso entender tudo. Não entendi a parte:

Teria que fazer algo parecido com o exemplo inicial do Joseleine, mas usando um campo que é estrangeiro (id_usuario).

G

opa, desculpe, foi uma desatenção, estava me referindo a id_arquivo.

Pra ser mais claro, usando as tabelas acima, quero mapear o entity VersaoArquivo, cuja chave é versao_arquivo e id_arquivo (estrangeira).

Posso simplesmente usar o modelo TestePk acima? Ou devo acrescentar alguma notação que mostre que id_arquivo é estrangeira?

Joseleine

Então.. a entity VersaoArquivo vc mapeia da maneira que eu expliquei as entities Teste e TestePk.. colocando os ids da chave composta na VersaoArquivoPk e um objeto do tipo VersaoArquivoPk na entity VersaoArquivo.

Na Entity VersaoArquivo, depois de mapear todos os campos, vc pode colocar um objeto do tipo Arquivo, para que fique mais fácil de saber qual é o arquivo exato de cada versão. Eu costumo fazer isso, mas se não fizer não trará problemas. Ficaria assim:
private Arquivo _arquivo;
   
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="ID_ARQUIVO", referencedColumnName="ID_ARQUIVO", insertable=false, updatable=false)
public Arquivo getArquivo() {
    return _arquivo;
}
    
public void setArquivo(Arquivo arquivo){
    this._arquivo = arquivo;
}

Lembrando que o "referencedColumnName" é como o id_arquivo é chamado na tabela Arquivo. O "insertable=false" e "updatable=false" é para que a jpa não tente inserir o arquivo novamente na tabela.

Na entity Arquivo, ficaria assim:

private List&lt;VersaoArquivo&gt; _versoes;

@OneToMany(cascade=CascadeType.ALL, mappedBy="arquivo", fetch=FetchType.EAGER)
public List&lt;VersaoArquivo&gt; getVersoes() {
    return _versoes;
}

public void setVersoes(List&lt;VersaoArquivo&gt; versoes) {
    this._versoes = versoes
}
Cabazzo

Essa família simpsons só tem fera!! rs!!

cleriston

Joseleine parabéns!
Depois de muito, muito procurar na internet este eh o unico tópico que trata disso.
Me ajudou muito
Abraços

cleriston
Joseleine, nao sei se é pq estou usando o toplink, mas a abordagem abaixo nao funcionou :
private Arquivo _arquivo;
   
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumn(name="ID_ARQUIVO", referencedColumnName="ID_ARQUIVO", insertable=false, updatable=false)
public Arquivo getArquivo() {
    return _arquivo;
}
    
public void setArquivo(Arquivo arquivo){
    this._arquivo = arquivo;
}

O problema ocorre qdo cria a tabela no banco, pois ele tenta criar o campo ID_ARQUIVO 2 vezes. Uma vez por causa da chave e a outra por causa do relaciomento. Quando a tabela já está criada este problema não ocorre

Eu resolvi fazendo algo do tipo :

@Transient
private Arquivo _arquivo;
   
public Arquivo getArquivo() {
    //traz o objeto do banco com o valor do ID_ARQUIVO do VersaoArquivoPk 
    return _arquivo;
}
    
public void setArquivo(Arquivo arquivo){
   //set o ID_ARQUIVO do VersaoArquivoPk com o ID_ARQUIVO do objeto arquivo
    this._arquivo = arquivo;
}
G

Amigos,

Muito bom esse tópico, me ajudou bastante!!! Mas ainda tenho uma dúvida:

Como eu faria o mapeamento do relacionamento se a minha tabela de chaves estrangeiras tivesse um campo adicional que não é chave para nenhuma tabela? Por exemplo :

  • estabelecimento: id_estabelecimento
  • configuracao: id_configuracao
  • estabelecimento_configuracao: id_estabelecimento, id_configuracao, valor

Onde valor é uma coluna que não pertence a nenhuma chave.

Abraço

Criado 30 de maio de 2008
Ultima resposta 9 de fev. de 2009
Respostas 12
Participantes 5