Qual anotação devo usar:@IdClass ou @EmbeddedId
-
03-07-2019 - |
Pergunta
O JPA
A especificação (Java Persistence API) tem 2 maneiras diferentes de especificar chaves compostas de entidade: @IdClass
e @EmbeddedId
.
Estou usando as duas anotações nas minhas entidades mapeadas, mas acaba sendo uma grande bagunça para pessoas que não estão muito familiarizadas com JPA
.
Quero adotar apenas uma maneira de especificar chaves compostas.Qual é realmente o melhor?Por que?
Solução
Eu considero isso @EmbeddedId
provavelmente é mais detalhado porque com @IdClass
Você não pode acessar todo o objeto de chave primária usando qualquer operador de acesso de campo. Usando o @EmbeddedId
Você pode fazer assim:
@Embeddable class EmployeeId { name, dataOfBirth }
@Entity class Employee {
@EmbeddedId EmployeeId employeeId;
...
}
Isso fornece uma noção clara dos campos que fazem a chave composta porque todos são agregados em uma classe que é acessada por um operador de acesso de campo.
Outra diferença com @IdClass
e @EmbeddedId
é quando se trata de escrever HQL:
Com @IdClass
você escreve:
select e.name from Employee e
e com @EmbeddedId
Você tem que escrever:
select e.employeeId.name from Employee e
Você precisa escrever mais texto para a mesma consulta. Alguns podem argumentar que isso difere de uma linguagem mais natural, como a promovida por IdClass
. Mas, na maioria das vezes, entender diretamente a partir da consulta que um determinado campo faz parte da chave composta é de ajuda inestimável.
Outras dicas
Descobri uma instância em que tive que usar o IDCLASS incorporado em vez de IDClass. Nesse cenário, há uma tabela de junção que possui colunas adicionais definidas. Tentei resolver esse problema usando o IDClass para representar a chave de uma entidade que representa explicitamente linhas na tabela de junção. Eu não conseguia fazer isso funcionando dessa maneira. Felizmente, "a persistência de Java com o Hibernate" tem uma seção dedicada a este tópico. Uma solução proposta era muito semelhante à minha, mas usava incorporado. Eu modelei meus objetos depois que aqueles do livro agora se comporta corretamente.
Existem três estratégias para usar uma chave primária composta:
- Marque como
@Embeddable
e adicione à sua propriedade normal da Classe A da entidade, marcada com@Id
. - Adicione à sua propriedade normal da classe A Classe A, marcada com
@EmbeddedId
. - Adicione propriedades à sua classe de entidade para todos os seus campos, marque -os com
@Id
e marque sua aula de entidade com@IdClass
, fornecendo a classe da sua classe de chave primária.
O uso de @Id
com uma classe marcada como @Embeddable
é a abordagem mais natural. o @Embeddable
De qualquer forma, a tag pode ser usada para valores incorporados de chave não primária. Ele permite que você trate a chave primária composta como uma única propriedade e permite a reutilização do @Embeddable
classe em outras tabelas.
A próxima abordagem mais natural é o uso do @EmbeddedId
marcação. Aqui, a classe chave primária não pode ser usada em outras tabelas, pois não é um @Embeddable
entidade, mas nos permite tratar a chave como um único atributo de alguma classe.
Finalmente, o uso do @IdClass
e @Id
As anotações nos permitem mapear a classe Primária composta usando as propriedades da própria entidade correspondentes aos nomes das propriedades na classe Key Primária. Os nomes devem corresponder (não há mecanismo para substituir isso), e a classe chave primária deve honrar as mesmas obrigações das outras duas técnicas. A única vantagem dessa abordagem é a capacidade de "ocultar" o uso da classe de chave primária a partir da interface da entidade anexante. o @IdClass
A anotação leva um parâmetro de valor do tipo de classe, que deve ser a classe a ser usada como a chave primária composta. Os campos que correspondem às propriedades da classe chave primária a ser usada devem ser anotados com @Id
.
Referência: http://www.apress.com/us/book/9781430228509
Pelo que eu sei, se o seu PK composto contém FK, é mais fácil e direto de usar @IdClass
Com @EmbeddedId
você tem que definir o mapeamento para sua coluna FK duas vezes, uma em @Embeddedable
e de uma vez por todas, ou seja, @ManyToOne
onde @ManyToOne
deve ser somente leitura (@PrimaryKeyJoinColumn
) porque você não pode ter uma coluna definida em duas variáveis (possíveis conflitos).
Então você tem que definir seu FK usando digitação simples @Embeddedable
.
No outro site usando @IdClass
esta situação pode ser tratada com muito mais facilidade, conforme mostrado em Chaves primárias por meio de relacionamentos OneToOne e ManyToOne:
Exemplo de anotação de id JPA 2.0 ManyToOne
...
@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 classe de identificação 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;
}
}
Eu acho que a principal vantagem é que poderíamos usar @GeneratedValue
para o ID ao usar o @IdClass
? Tenho certeza que não podemos usar @GeneratedValue
por @EmbeddedId
.
Chave composta não deve ter um @Id
propriedade quando @EmbeddedId
é usado.
Com o incorporado, você pode usar a cláusula IN no HQL, por exemplo: FROM Entity WHERE id IN :ids
onde o ID é um incorporado, enquanto é dor alcançar o mesmo resultado com o IDClass, você vai querer fazer algo como FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN