@UniqueConstraint e @Column (unique = true) nell'annotazione di ibernazione


104

Qual è la differenza tra @UniqueConstraint e @Column (unique = true) ?

Per esempio:

@Table(
   name = "product_serial_group_mask", 
   uniqueConstraints = {@UniqueConstraint(columnNames = {"mask", "group"})}
)

E

@Column(unique = true)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private ProductSerialMask mask;

@Column(unique = true)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private Group group;

2
Nota: con Hibernate 5.4, quando ho aggiunto unique=true, l'indice non è stato aggiunto dallo schema di aggiornamento automatico. @UniqueConstraintl'ha fatto apparire. Potrebbe essere un bug.
Ondra Žižka

Risposte:


147

Come detto prima, @Column(unique = true)è una scorciatoia per UniqueConstraintquando è solo un singolo campo.

Dall'esempio che hai fornito, c'è un'enorme differenza tra i due.

@Column(unique = true)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private ProductSerialMask mask;

@Column(unique = true)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private Group group;

Questo codice implica che entrambi maske groupdevono essere unici, ma separatamente. Ciò significa che se, ad esempio, hai un record con mask.id = 1 e cerchi di inserire un altro record con mask.id = 1 , otterrai un errore, perché quella colonna dovrebbe avere valori univoci. Lo stesso vale per il gruppo.

D'altro canto,

@Table(
   name = "product_serial_group_mask", 
   uniqueConstraints = {@UniqueConstraint(columnNames = {"mask", "group"})}
)

Implica che i valori di maschera + gruppo combinati dovrebbero essere univoci. Ciò significa che puoi avere, ad esempio, un record con mask.id = 1 e group.id = 1 , e se provi a inserire un altro record con mask.id = 1 e group.id = 2 , verrà inserito con successo, mentre nel primo caso no.

Se desideri che sia la maschera che il gruppo siano unici separatamente ea livello di classe, dovresti scrivere il codice come segue:

@Table(
        name = "product_serial_group_mask",
        uniqueConstraints = {
                @UniqueConstraint(columnNames = "mask"),
                @UniqueConstraint(columnNames = "group")
        }
)

Questo ha lo stesso effetto del primo blocco di codice.


Una volta creato il vincolo univoco, posso fare riferimento al vincolo in base al nome nel mio repository JPA per interrogarlo?
jDub9

@ jDub9 Non è possibile interrogare un indice. Puoi interrogare la maschera e le colonne del gruppo, in una query, e userà quell'indice per un'elaborazione più veloce (se sei fortunato), ma non puoi semplicemente interrogare un indice.
Dalibor Filus

Attenzione però che columnNames devono essere nomi effettivi nel database. Dovrebbe essere mask_ide group_idse usi la strategia di denominazione predefinita.
vitro

27

Dalla documentazione di Java EE:

public abstract boolean unique

(Facoltativo) Indica se la proprietà è una chiave univoca. Questa è una scorciatoia per l'annotazione UniqueConstraint a livello di tabella ed è utile quando il vincolo di chiave univoco è solo un singolo campo. Questo vincolo si applica in aggiunta a qualsiasi vincolo imposto dalla mappatura della chiave primaria e ai vincoli specificati a livello di tabella.

Vedi doc


quindi quando utilizzo questo codice: @Column (unique = true) @ManyToOne (optional = false, fetch = FetchType.EAGER) private ProductSerialMask mask; @Column (unique = true) @ManyToOne (optional = false, fetch = FetchType.EAGER) gruppo gruppo privato; Ho due indici ma quando uso in un altro modo ho un indice che si combina di due colonne?
navid_gh

22

Oltre alla risposta di Boaz ...

@UniqueConstraintti permette di dare un nome al vincolo , mentre @Column(unique = true)genera un nome casuale (es UK_3u5h7y36qqa13y3mauc5xxayq.).

A volte può essere utile sapere a quale tabella è associato un vincolo. Per esempio:

@Table(
   name = "product_serial_group_mask", 
   uniqueConstraints = {
      @UniqueConstraint(
          columnNames = {"mask", "group"},
          name="uk_product_serial_group_mask"
      )
   }
)

5

Oltre alle risposte di @ Boaz e @ vegemite4me ....

Con l'implementazione ImplicitNamingStrategyè possibile creare regole per denominare automaticamente i vincoli. Nota che aggiungi la tua strategia di denominazione metadataBuilderdurante l'inizializzazione di Hibernate:

metadataBuilder.applyImplicitNamingStrategy(new MyImplicitNamingStrategy());

Funziona per @UniqueConstraint, ma non per @Column(unique = true), che genera sempre un nome casuale (ad esempio UK_3u5h7y36qqa13y3mauc5xxayq).

C'è una segnalazione di bug per risolvere questo problema, quindi se puoi, vota lì per implementarlo. Qui: https://hibernate.atlassian.net/browse/HHH-11586

Grazie.

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.