@UniqueConstraint dan @Column (unique = true) dalam anotasi hibernasi

104

Apa perbedaan antara @UniqueConstraint dan @Column (unique = true) ?

Sebagai contoh:

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

Dan

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

@Column(unique = true)
@ManyToOne(optional = false, fetch = FetchType.EAGER)
private Group group;
navid_gh
sumber
2
Catatan: Dengan Hibernate 5.4, ketika saya menambahkan unique=true, indeks tidak ditambahkan oleh skema pembaru otomatis. @UniqueConstraintmembuatnya tampak. Bisa jadi bug.
Ondra Žižka

Jawaban:

147

Seperti yang dikatakan sebelumnya, @Column(unique = true)ini adalah jalan pintas UniqueConstraintketika hanya satu bidang.

Dari contoh yang Anda berikan, ada perbedaan besar antara keduanya.

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

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

Kode ini menyiratkan bahwa keduanya maskdan groupharus unik, tetapi terpisah. Artinya, jika, misalnya, Anda memiliki record dengan mask.id = 1 dan mencoba memasukkan record lain dengan mask.id = 1 , Anda akan mendapatkan error, karena kolom tersebut harus memiliki nilai yang unik. Hal yang sama berlaku untuk grup.

Di samping itu,

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

Menyiratkan bahwa nilai gabungan mask + group harus unik. Artinya, Anda dapat memiliki, misalnya, catatan dengan mask.id = 1 dan group.id = 1 , dan jika Anda mencoba memasukkan catatan lain dengan mask.id = 1 dan group.id = 2 , itu akan disisipkan berhasil, sedangkan dalam kasus pertama tidak.

Jika Anda ingin mask dan grup menjadi unik secara terpisah dan pada tingkat kelas, Anda harus menulis kode sebagai berikut:

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

Ini memiliki efek yang sama seperti blok kode pertama.

Glauber Néspoli
sumber
Setelah batasan unik dibuat, apakah saya dapat merujuk batasan berdasarkan nama di Repositori JPA saya untuk menanyakannya?
jDub9
@ jDub9 Anda tidak dapat meminta indeks. Anda dapat membuat kueri mask dan kolom grup, dalam satu kueri, dan itu akan menggunakan indeks itu untuk pemrosesan yang lebih cepat (jika Anda beruntung), tetapi Anda tidak bisa begitu saja meminta indeks.
Dalibor Filus
Berhati-hatilah meskipun nama kolom harus nama sebenarnya dalam database. Ini harus mask_iddan group_idjika Anda menggunakan strategi penamaan default.
vitro
27

Dari dokumentasi Java EE:

public abstract boolean unique

(Opsional) Apakah properti tersebut adalah kunci unik. Ini adalah pintasan untuk anotasi UniqueConstraint di tingkat tabel dan berguna jika batasan kunci unik hanya satu bidang. Batasan ini berlaku sebagai tambahan untuk batasan apa pun yang diperlukan oleh pemetaan kunci utama dan batasan yang ditentukan pada tingkat tabel.

Lihat dok

Boaz
sumber
jadi ketika saya menggunakan kode ini: @Column (unique = true) @ManyToOne (opsional = false, fetch = FetchType.EAGER) private ProductSerialMask mask; @Column (unique = true) @ManyToOne (opsional = false, fetch = FetchType.EAGER) grup grup pribadi; Saya memiliki dua indeks tetapi ketika menggunakan cara lain saya memiliki satu indeks yang merupakan gabungan dari dua kolom?
navid_gh
22

Selain jawaban Boas ....

@UniqueConstraintmemungkinkan Anda untuk memberi nama batasan , sementara @Column(unique = true)menghasilkan nama acak (misalnya UK_3u5h7y36qqa13y3mauc5xxayq).

Terkadang akan sangat membantu untuk mengetahui tabel apa yang dikaitkan dengan batasan. Misalnya:

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

Selain jawaban @ Boaz dan @ vegemite4me ....

Dengan mengimplementasikan ImplicitNamingStrategyAnda dapat membuat aturan untuk menamai batasan secara otomatis. Perhatikan Anda menambahkan strategi penamaan Anda ke metadataBuilderselama inisialisasi Hibernate:

metadataBuilder.applyImplicitNamingStrategy(new MyImplicitNamingStrategy());

Ini berfungsi untuk @UniqueConstraint, tetapi tidak untuk @Column(unique = true), yang selalu menghasilkan nama acak (misalnya UK_3u5h7y36qqa13y3mauc5xxayq).

Ada laporan bug untuk mengatasi masalah ini, jadi jika Anda bisa, silakan pilih di sana untuk menerapkannya. Di sini: https://hibernate.atlassian.net/browse/HHH-11586

Terima kasih.

MarcG
sumber