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?

Foi útil?

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 @Ide 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

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top