Dúvida em chaves compostas com JPA

11 respostas
remarques

Estou tentando desenvolver uma plaicação utilizando JPA e estou com a seguinte dificuldade:

Tenho uma entidade, cuja chave é composta.
Para isso estou utilizando a anotaçao @EmbeddedId.
Até aí tudo bem.

O problema é que cada um dos atributos dessa chave é uma outra entidade.
Com isso, sempre é gerada a segunte exception:

"Entity [class Entidade.UnidadeFuncionario] uses [class Entidade.UnidadeFuncionarioId] as embedded id class whose access-type has been determined as [FIELD]. But [class Entidade.UnidadeFuncionarioId] does not define any [FIELD]. It is likely that you have not provided sufficient metadata in your id class [class Entidade.UnidadeFuncionarioId]."

@Entity
public class UnidadeFuncionario implements Serializable {
    private static final long serialVersionUID = 1L;
    
    @EmbeddedId
    private UnidadeFuncionarioId id;
    private int pesoUnidade;
    //getter and setters
@Embeddable
public class UnidadeFuncionarioId implements Serializable{

   private Funcionario funcionario;
   private Unidade unidade;
   //Getter and setter

Alguém ajuda?

11 Respostas

danieldestro

Tem algo errado nessa chave ai.

Ela deveria conter apenas os valores (campos/atributos) que compõe de fato a chave, não outras entidades.

remarques

Acontece que o que identifica essa classe é exatamente o Indicador e a Unidade. Nesse caso devo usar só o ID?

V

Estou exatamente com o mesmo problema…

Em outro projeto aqui na empresa que usa apenas Hibernate, eu consigo fazer isso, porém no JPA não está dando certo

B

remarques:
Acontece que o que identifica essa classe é exatamente o Indicador e a Unidade. Nesse caso devo usar só o ID?

Não, o que identifica essa classe são os IDs de funcionario e de unidade, não os próprios funcionários e as unidades. Ou seja, coloque os IDs (Integer, String, o que for) deles lá.

Pode até falar “Mas isso não é muito OO!”

Eu digo “Bem vindo à impendância objeto-relacional!”

Duas leituras p/ você:

http://java.sun.com/javaee/5/docs/tutorial/doc/bnbqa.html#bnbqg
http://weblogs.java.net/blog/bleonard/archive/2006/11/using_composite.html

V

Então com JPA eu não consigo, por exemplo, chegar em:

tarefa.id.projeto.algumcampo

eu sempre vou ficar limitado ao código ? a partir dele vou ter q fazer outra consulta pra chegar ao meu “projeto” ?

B

Não ficará limitado. Até por que tarefa.projeto tipicamente é um relacionamento Muitos-Para-Um, implementado como

(...)
Projeto projeto;

@ManyToOne(opção=etc, foo="bar")
public Projeto getProjeto() {
    return this.projeto;
}
public Projeto setProjeto(Projeto projeto) {
    this.projeto = projeto;
}
(...)

Lembre-se que, o que define o comportamento de uma classe são seus métodos, o que é persistido são seus atributos. Ou seja, existem os setters e getters da classe que mapeiam os atributos, mas também existem outros métodos, aqueles que fazem parte da sua lógica de negócio. Ambos os tipos podem estar muito bem na mesma classe.

remarques

Mas se do relacionamento entre tarefa.projeto eu tenho por exemplo um campo data em que a tarefa foi realizada, preciso necessariamente criar uma outra entidade, pra acrescentar esse campo, não é?
E aí nesse caso, se eu precisar de alguma informação da tarefa, por exemplo, vou precisar usar o id para fazer uma consulta, é isso?

V

Desculpe, mas não entendi… vou colocar aqui o que estou tentando fazer:

@Entity
public class BeneficiarioCarencia implements Serializable {

    @EmbeddedId
    private BeneficiarioCarenciaPK id;
    
    @Column(name="datacarencia", nullable=false)
    @Temporal(TemporalType.DATE)
    private Date dataCarencia;

    getters, setters, etc...
@Embeddable
public class BeneficiarioCarenciaPK implements Serializable {

    @ManyToOne
    @JoinColumn(name="codbeneficiario", referencedColumnName="codbeneficiario", nullable=false)
    private Beneficiario beneficiario;
    
    @ManyToOne
    @JoinColumn(name="codcarencia", referencedColumnName="codcarencia", nullable=false)
    private Carencia carencia;

    getters, setters, etc...

o certo então seria eu fazer a classe BeneficiarioCarenciaPK assim:

@Embeddable
public class BeneficiarioCarenciaPK implements Serializable {

    @Column(name="codbeneficiario", nullable=false)
    private String codbeneficiario;
    
    @Column(name="codcarencia", nullable=false)
    private String codcarencia;

    getters, setters, etc...

se eu fizer dessa forma, como eu chego em:
carenciaBeneficiario.id.codbeneficiario.nome ??

B
@Entity
public class BeneficiarioCarencia implements Serializable {

    @EmbeddedId
    private BeneficiarioCarenciaPK id;
    
    @Column(name="datacarencia", nullable=false)
    @Temporal(TemporalType.DATE)
    private Date dataCarencia;

    @ManyToOne
    @JoinColumn(name="codbeneficiario", referencedColumnName="codbeneficiario", nullable=false)
    private Beneficiario beneficiario;
    
    @ManyToOne
    @JoinColumn(name="codcarencia", referencedColumnName="codcarencia", nullable=false)
    private Carencia carencia;

    getters, setters, etc...
@Embeddable
public class BeneficiarioCarenciaPK implements Serializable {

    @Column(name="codbeneficiario", nullable=false)
    private String codbeneficiario;
    
    @Column(name="codcarencia", nullable=false)
    private String codcarencia;

    getters, setters, etc...

carenciaBeneficiario.beneficiario.nome

B

Aliás, será que não funciona só com @Id em cima de ambos os campos, sem precisar dessa outra classe de PK?

danieldestro

Cara, que complicação você criou. Não confunda-se!

Não é pela chave (PK) que você vai acessar os relacionamentos. A PK serve para definir o identificador do objeto (ID). Os relacionamentos ainda existirão.

pessoa.id
pessoa.nome
pessoa.idade
pessoa.endereco.logradouro
pessoa.endereco.numero
pessoa.filho.id
pessoa.filho.nome
pessoa.filho.endereco.logradouro

Entendeu?

Criado 28 de abril de 2008
Ultima resposta 29 de abr. de 2008
Respostas 11
Participantes 4