Quale annotazione dovrei usare: @IdClass o @EmbeddedId

La specifica JPA (Java Persistence API) ha 2 modi diversi per specificare le chiavi composite dell’ quadro: @IdClass e @IdClass .

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

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

Ritengo che @EmbeddedId sia probabilmente più dettagliato perché con @IdClass non è ansible accedere all’intero object della chiave primaria utilizzando qualsiasi operatore di accesso ai campi. Usando @EmbeddedId puoi fare così:

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

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

Un’altra differenza con @IdClass e @IdClass è quando si tratta di scrivere HQL:

Con @IdClass scrivi:

  selezionare e.name da Employee e 

e con @EmbeddedId devi scrivere:

  selezionare e.employeeId.name da Employee e 

Devi scrivere più testo per la stessa query. Alcuni potrebbero obiettare che ciò differisce da un linguaggio più naturale come quello promosso da IdClass . Ma la maggior parte delle volte capendo dalla query che un dato campo fa parte della chiave composta è di aiuto inestimabile.

Ho scoperto un’istanza in cui dovevo usare EmbeddedId invece di IdClass. In questo scenario è presente una tabella di join con colonne aggiuntive definite. Ho provato a risolvere questo problema utilizzando IdClass per rappresentare la chiave di un’ quadro 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 del libro che ora si comporta correttamente.

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

Con @EmbeddedId devi definire la mapping per la colonna FK due volte, onece in @Embeddedable e una volta for come @ManyToOne dove @ManyToOne deve essere di sola lettura ( @PrimaryKeyJoinColumn ) perché non puoi avere una colonna impostata in due variabili (possibili conflitti).
Quindi devi impostare il tuo FK usando il tipo semplice in @Embeddedable .

Sull’altro sito che usa @IdClass questa situazione può essere gestita molto più facilmente, come mostrato in Chiavi primarie tramite OneToOne e ManyToOne Relationships :

Esempio di annotazione ID ManyToOne 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 class 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; } } 

Esistono tre strategie per utilizzare una chiave primaria composta:

  • Contrassegnalo come @Embeddable e aggiungi alla tua class di entity framework una proprietà normale per esso, contrassegnata con @Id .
  • Aggiungi alla tua class entity framework una proprietà normale per esso, contrassegnata con @EmbeddedId .
  • Aggiungi proprietà alla tua class di quadro per tutti i suoi campi, contrassegnali con @Id e contrassegna la tua class di quadro con @IdClass , fornendo la class della class di chiave primaria.

L’uso di @Id con una class contrassegnata come @Embeddable è l’approccio più naturale. Il tag @Embeddable può essere comunque utilizzato per valori incorporabili di chiavi non primarie. Ti consente di trattare la chiave primaria composta come una singola proprietà e consente il riutilizzo della class @Embeddable in altre tabelle.

Il prossimo approccio più naturale è l’uso del tag @EmbeddedId . Qui, la class chiave primaria non può essere utilizzata in altre tabelle poiché non è un’ quadro @Embeddable , ma ci consente di trattare la chiave come un singolo attributo di una class.

Infine, l’uso delle annotazioni @IdClass e @IdClass ci consente di mappare la class di chiavi primaria composta utilizzando le proprietà dell’ quadro stessa corrispondenti ai nomi delle proprietà nella class di chiavi primaria. I nomi devono corrispondere (non esiste un meccanismo per sovrascrivere questo) e la class chiave primaria deve onorare gli stessi obblighi delle altre due tecniche. L’unico vantaggio di questo approccio è la sua capacità di “hide” l’uso della class di chiave primaria dall’interfaccia dell’ quadro che lo include. L’annotazione @IdClass accetta un parametro value di tipo Class, che deve essere la class da utilizzare come chiave primaria composta. I campi che corrispondono alle proprietà della class di chiavi primaria da utilizzare devono essere tutti annotati con @Id .

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

Penso che il vantaggio principale sia che potremmo usare @GeneratedValue per l’id quando si usa @IdClass ? Sono sicuro che non possiamo usare @GeneratedValue per @GeneratedValue .

La chiave composita non deve avere una proprietà @Id quando viene utilizzato @EmbeddedId .

Con EmbeddedId è ansible utilizzare la clausola IN in HQL, ad esempio: FROM Entity WHERE id IN :ids dove id è un EmbeddedId mentre è difficile ottenere lo stesso risultato con IdClass si vorrà fare qualcosa come FROM Entity WHERE idPartA = :idPartA0 AND idPartB = :idPartB0 .... OR idPartA = :idPartAN AND idPartB = :idPartBN