Qual anotação devo usar: @IdClass ou @EmbeddedId

A especificação JPA (Java Persistence API) possui duas maneiras diferentes de especificar chaves compostas de entidade: @IdClass e @EmbeddedId .

Estou usando as duas annotations em minhas entidades mapeadas, mas isso acaba sendo uma grande confusão para pessoas que não estão muito familiarizadas com o JPA .

Eu quero adotar apenas uma maneira de especificar chaves compostas. Qual deles é realmente o melhor? Por quê?

Eu considero que @EmbeddedId é provavelmente mais detalhado porque com @IdClass você não pode acessar o object de chave primária inteiro usando qualquer operador de access de campo. Usando o @EmbeddedId você pode fazer assim:

 @Embeddable class EmployeeId { name, dataOfBirth } @Entity class Employee { @EmbeddedId EmployeeId employeeId; ... } 

Isso dá uma noção clara dos campos que compõem a chave composta, porque todos eles são agregados em uma class que é acessada por um operador de access de campo.

Outra diferença com @IdClass e @EmbeddedId é quando se trata de escrever HQL:

Com @IdClass você escreve:

  selecione e.name do funcionário e 

e com @EmbeddedId você tem que escrever:

  selecione e.employeeId.name do Funcionário e 

Você tem que escrever mais texto para a mesma consulta. Alguns podem argumentar que isso difere de uma linguagem mais natural como a promovida pelo IdClass . Mas, na maioria das vezes, entender desde a consulta que um dado campo faz parte da chave composta é de ajuda inestimável.

Eu descobri uma instância onde eu tive que usar EmbeddedId em vez de IdClass. Nesse cenário, há uma tabela de junit que possui colunas adicionais definidas. Eu tentei resolver esse problema usando IdClass para representar a chave de uma entidade que representa explicitamente linhas na tabela de associação. Eu não consegui fazer isso funcionar dessa maneira. Felizmente, “Java Persistence With Hibernate” possui uma seção dedicada a este tópico. Uma solução proposta era muito parecida com a minha, mas ela usava o EmbeddedId. Eu modelei meus objects depois daqueles no livro que agora se comporta corretamente.

Tanto quanto eu sei se o seu PK composto contém FK, é mais fácil e mais simples usar @IdClass

Com @EmbeddedId você tem que definir o mapeamento para sua coluna FK duas vezes, onece em @Embeddedable e uma vez para como ie @ManyToOne onde @ManyToOne tem que ser somente leitura ( @PrimaryKeyJoinColumn ) porque você não pode ter uma coluna configurada em duas variables (possíveis conflitos).
Então você tem que definir o seu FK usando o tipo simples em @Embeddedable .

No outro site usando @IdClass essa situação pode ser tratada de maneira muito mais fácil, conforme mostrado nas Chaves Primárias através dos Relacionamentos OneToOne e ManyToOne :

Exemplo de anotação de ID ManyToOne do JPA 2.0

 ... @Entity @IdClass(PhonePK.class) public class Phone { @Id private String type; @ManyToOne @Id @JoinColumn(name="OWNER_ID", referencedColumnName="EMP_ID") private Employee owner; ... } 

Exemplo de class id do JPA 2.0

 ... public class PhonePK { private String type; private long owner; public PhonePK() {} public PhonePK(String type, long owner) { this.type = type; this.owner = owner; } public boolean equals(Object object) { if (object instanceof PhonePK) { PhonePK pk = (PhonePK)object; return type.equals(pk.type) && owner == pk.owner; } else { return false; } } public int hashCode() { return type.hashCode() + owner; } } 

Existem três estratégias para usar uma chave primária composta:

  • Marque-o como @Embeddable e adicione à sua class de entidade uma propriedade normal para ele, marcada com @Id .
  • Adicione à sua class de entidade uma propriedade normal para ela, marcada com @EmbeddedId .
  • Adicione propriedades à sua class de entidade para todos os seus campos, marque-as com @Id e marque sua class de entidade com @IdClass , fornecendo a class de sua class de chave primária.

O uso de @Id com uma class marcada como @Embeddable é a abordagem mais natural. A tag @Embeddable pode ser usada para valores incorporáveis ​​de chave não primária de qualquer forma. Ele permite tratar a chave primária composta como uma única propriedade e permite a reutilização da class @Embeddable em outras tabelas.

A próxima abordagem mais natural é o uso da tag @EmbeddedId . Aqui, a class de chave primária não pode ser usada em outras tabelas, pois não é uma entidade @Embeddable , mas nos permite tratar a chave como um único atributo de alguma class.

Finalmente, o uso das annotations @IdClass e @Id nos permite mapear a class de chave primária composta usando propriedades da própria entidade correspondentes aos nomes das propriedades na class de chave primária. Os nomes devem corresponder (não há mecanismo para anular isso) e a class de chave primária deve honrar as mesmas obrigações que com as outras duas técnicas. A única vantagem dessa abordagem é sua capacidade de “ocultar” o uso da class de chave primária da interface da entidade envolvente. A anotação @IdClass recebe um parâmetro de valor do tipo Classe, que deve ser a class a ser usada como chave primária composta. Os campos que correspondem às propriedades da class de chave primária a ser usada devem ser anotados com @Id .

Referência: http://www.apress.com/us/book/9781430228509

Eu acho que a principal vantagem é que poderíamos usar @GeneratedValue para o id ao usar o @IdClass ? Tenho certeza de que não podemos usar @GeneratedValue para @GeneratedValue .

Chave composta não deve ter uma propriedade @Id quando @Id é usado.

Com EmbeddedId você pode usar a cláusula IN em HQL, por exemplo: FROM Entity WHERE id IN :ids que id é um EmbeddedId, enquanto é difícil atingir o mesmo resultado com IdClass, você desejará fazer algo como FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

    Intereting Posts