Quale annotazione dovrei usare: @IdClass o @EmbeddedId


128

La specifica JPA(Java Persistence API) ha 2 modi diversi per specificare le chiavi composite di entità: @IdClasse @EmbeddedId.

Sto usando entrambe le annotazioni sulle mie entità mappate, ma risulta essere un gran casino per le persone che non hanno molta familiarità JPA.

Voglio adottare un solo modo per specificare le chiavi composite. Qual è davvero il migliore? Perché?

Risposte:


86

Ritengo che @EmbeddedIdsia probabilmente più prolisso perché con @IdClasste non puoi accedere all'intero oggetto chiave primaria utilizzando alcun operatore di accesso al campo. Usando @EmbeddedIdpuoi fare così:

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

Ciò fornisce una chiara idea dei campi che compongono la chiave composita perché sono tutti aggregati in una classe a cui si accede tramite un operatore di accesso al campo.

Un'altra differenza con @IdClassed @EmbeddedIdè quando si tratta di scrivere HQL:

Con @IdClasste scrivi:

seleziona e.name da Employee e

e con @EmbeddedIdte devi scrivere:

selezionare e.employeeId.name da Employee e

Devi scrivere più testo per la stessa query. Alcuni potrebbero sostenere che questo differisce da un linguaggio più naturale come quello promosso da IdClass. Ma la maggior parte delle volte capire dalla query che un determinato campo fa parte della chiave composita è di aiuto inestimabile.


10
Anche se sono d'accordo con la spiegazione di cui sopra, vorrei anche aggiungere un caso d'uso unico, @IdClassanche se preferisco @EmbeddedIdnella maggior parte delle situazioni (ho imparato questo da una sessione di Antonio Goncalves. Ciò che ha suggerito è che potremmo usare il @IdClasscaso il composito la classe chiave non è accessibile o proviene da un altro modulo o codice legacy in cui non è possibile aggiungere un'annotazione. In questi scenari @IdClassci darà un modo il nostro
Gaurav Rawat,

1
Penso che sia possibile che i casi per usare l' @IdClassannotazione data da @Gaurav sia la vera ragione per cui la specifica JPA elenca entrambi i metodi per creare una chiave composita .. @IdClasse@EmbeddidId
kapad,

20

Esistono tre strategie per utilizzare una chiave primaria composta:

  • Contrassegnalo come @Embeddablee aggiungi alla tua classe di entità una proprietà normale, contrassegnata con @Id.
  • Aggiungi alla tua classe di entità una proprietà normale, contrassegnata con @EmbeddedId.
  • Aggiungi proprietà alla tua classe di entità per tutti i suoi campi, contrassegnale con @Ide contrassegna la tua classe di entità @IdClass, fornendo la classe della tua classe chiave primaria.

L'uso di @Idcon una classe contrassegnata come @Embeddableè l'approccio più naturale. Il @Embeddabletag può essere comunque utilizzato per i valori incorporabili della chiave non primaria. Ti consente di trattare la chiave primaria composta come un'unica proprietà e consente il riutilizzo della @Embeddableclasse in altre tabelle.

Il prossimo approccio più naturale è l'uso del @EmbeddedIdtag. Qui, la classe chiave primaria non può essere utilizzata in altre tabelle poiché non è @Embeddableun'entità, ma ci consente di trattare la chiave come un singolo attributo di una classe.

Infine, l'uso delle annotazioni @IdClasse @Idci consente di mappare la classe di chiave primaria composta utilizzando le proprietà dell'entità stessa corrispondenti ai nomi delle proprietà nella classe di chiave primaria. I nomi devono corrispondere (non esiste alcun meccanismo per sovrascriverlo) e la classe chiave primaria deve rispettare gli stessi obblighi delle altre due tecniche. L'unico vantaggio di questo approccio è la sua capacità di "nascondere" l'uso della classe chiave primaria dall'interfaccia dell'entità che lo racchiude. L' @IdClassannotazione accetta un parametro value del tipo Class, che deve essere la classe da utilizzare come chiave primaria composta. I campi che corrispondono alle proprietà della classe di chiave primaria da utilizzare devono essere tutti annotati @Id.

Riferimento: http://www.apress.com/us/book/9781430228509


17

Ho scoperto un'istanza in cui ho dovuto usare EmbeddedId invece di IdClass. In questo scenario è presente una tabella di join in cui sono definite colonne aggiuntive. Ho tentato di risolvere questo problema utilizzando IdClass per rappresentare la chiave di un'entità che rappresenta esplicitamente le righe nella tabella di join. Non riuscivo a farlo funzionare in questo modo. Per fortuna "Java Persistence With Hibernate" ha una sezione dedicata a questo argomento. Una soluzione proposta era molto simile alla mia ma utilizzava invece EmbeddedId. Ho modellato i miei oggetti dopo quelli nel libro, ora si comporta correttamente.


13

Per quanto ne so se il tuo PK composito contiene FK è più facile e più semplice da usare @IdClass

Con questo @EmbeddedIddevi definire il mapping per la tua colonna FK due volte, onece in @Embeddedablee once for as ie @ManyToOnedove @ManyToOnedeve essere di sola lettura ( @PrimaryKeyJoinColumn) perché non puoi avere una colonna impostata in due variabili (possibili conflitti).
Quindi devi impostare il tuo FK usando un semplice digitazione @Embeddedable.

Sull'altro sito che utilizza @IdClassquesta situazione può essere gestito molto più facilmente, come mostrato nelle chiavi primarie tramite le relazioni OneToOne e ManyToOne :

Esempio di annotazione dell'ID ManyToOne di 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;
    ...
}

Esempio di classe ID 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;
    }
}

1
Non dimenticare di aggiungere getter alla tua classe PK
Sonata,

@Sonata perché abbiamo bisogno dei getter? L'ho provato senza alcun getter / setter e funziona benissimo
xagaffar,

Grazie per l'esempio della classe id! Anche se alla fine ho dovuto implementare anche Serializable. Inoltre potrebbe anche aggiungere getter e setter, specialmente se il tuo IDE può generarli automaticamente.
Starwarswii,

8

Penso che il vantaggio principale sia che potremmo usare @GeneratedValueper l'id quando si usa il @IdClass? Sono sicuro che non possiamo usare @GeneratedValueper @EmbeddedId.


1
Non è possibile utilizzare @GeneratedValue in Embeddedid ??
Kayser,

1
L'ho usato con successo con EmbeddedId ma a quanto pare il suo supporto varia a seconda del DB. Questo vale anche per l'utilizzo con IdClass. La specifica dice: "L'annotazione GeneratedValue può essere utilizzata solo per le chiavi primarie semplici (cioè non composite)."
BPS,

4

La chiave composita non deve avere una @Idproprietà quando @EmbeddedIdviene utilizzata.


1

Con EmbeddedId puoi usare la clausola IN in HQL, ad esempio: FROM Entity WHERE id IN :idsdove id è un EmbeddedId mentre è difficile ottenere lo stesso risultato con IdClass vorrai fare qualcosa di simileFROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.