Dúvida em chaves compostas com JPA

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].”

[code]@Entity
public class UnidadeFuncionario implements Serializable {
private static final long serialVersionUID = 1L;

@EmbeddedId
private UnidadeFuncionarioId id;
private int pesoUnidade;
//getter and setters

[/code]

[code]@Embeddable
public class UnidadeFuncionarioId implements Serializable{

private Funcionario funcionario;
private Unidade unidade;
//Getter and setter
[/code]

Alguém ajuda?

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.

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

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

[quote=remarques]Acontece que o que identifica essa classe é exatamente o Indicador e a Unidade. Nesse caso devo usar só o ID?
[/quote]

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

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” ?

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.

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?

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

@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

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

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?