@UniqueConstraint i @Column (unique = true) w adnotacji hibernacji

104

Jaka jest różnica między @UniqueConstraint i @Column (unique = true) ?

Na przykład:

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

I

@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
źródło
2
Uwaga: W Hibernate 5.4, kiedy dodałem unique=true, indeks nie został dodany przez automatyczną aktualizację schematu. @UniqueConstraintsprawiło, że się pojawiło. To może być błąd.
Ondra Žižka

Odpowiedzi:

147

Jak wspomniano wcześniej, @Column(unique = true)jest to skrót do, UniqueConstraintgdy jest to tylko jedno pole.

Z podanego przykładu wynika, że ​​między nimi jest ogromna różnica.

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

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

Ten kod oznacza, że ​​oba maski groupmuszą być unikalne, ale oddzielnie. Oznacza to, że jeśli na przykład masz rekord z wartością mask.id = 1 i spróbujesz wstawić inny rekord z wartością mask.id = 1 , otrzymasz błąd, ponieważ ta kolumna powinna mieć unikalne wartości. To samo dotyczy grupy.

Z drugiej strony,

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

Sugeruje, że połączone wartości maska ​​+ grupa powinny być niepowtarzalne. Oznacza to, że możesz mieć na przykład rekord z mask.id = 1 i group.id = 1 , a jeśli spróbujesz wstawić inny rekord z mask.id = 1 i group.id = 2 , zostanie on wstawiony pomyślnie, podczas gdy w pierwszym przypadku nie.

Jeśli chciałbyś, aby zarówno maska, jak i grupa były unikalne osobno, a do tego na poziomie klasy, musisz napisać kod w następujący sposób:

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

Ma to taki sam efekt jak pierwszy blok kodu.

Glauber Néspoli
źródło
Czy po utworzeniu ograniczenia unikalności mogę odwołać się do ograniczenia według nazwy w moim repozytorium JPA, aby zapytać o to?
jDub9
@ jDub9 Nie można zapytać o indeks. Możesz wysłać zapytanie do kolumn maski i grupy w jednym zapytaniu i użyje tego indeksu do szybszego przetwarzania (jeśli masz szczęście), ale nie możesz po prostu zapytać o indeks.
Dalibor Filus
Uważaj jednak, że nazwy kolumn muszą być rzeczywistymi nazwami w bazie danych. Powinno być mask_idi group_idjeśli używasz domyślnej strategii nazewnictwa.
vitro
27

Z dokumentacji Java EE:

public abstract boolean unique

(Opcjonalnie) Określa, czy właściwość jest unikalnym kluczem. Jest to skrót do adnotacji UniqueConstraint na poziomie tabeli i jest przydatny, gdy ograniczenie klucza unikatowego jest tylko jednym polem. To ograniczenie ma zastosowanie dodatkowo do wszelkich ograniczeń wynikających z mapowania klucza podstawowego oraz do ograniczeń określonych na poziomie tabeli.

Zobacz dok

Boaz
źródło
więc kiedy używam tego kodu: @Column (unique = true) @ManyToOne (optional = false, fetch = FetchType.EAGER) prywatna maska ​​ProductSerialMask; @Column (unique = true) @ManyToOne (opcjonalne = false, fetch = FetchType.EAGER) grupa prywatna; Mam dwa indeksy, ale w inny sposób mam jeden indeks, który składa się z dwóch kolumn?
navid_gh
22

Oprócz odpowiedzi Boaza ...

@UniqueConstraintpozwala nazwać ograniczenie , podczas gdy @Column(unique = true)generuje losową nazwę (np UK_3u5h7y36qqa13y3mauc5xxayq.).

Czasami warto wiedzieć, z jaką tabelą jest skojarzone ograniczenie. Na przykład:

@Table(
   name = "product_serial_group_mask", 
   uniqueConstraints = {
      @UniqueConstraint(
          columnNames = {"mask", "group"},
          name="uk_product_serial_group_mask"
      )
   }
)
vegemite4me
źródło
5

Oprócz odpowiedzi @ Boaz i @ vegemite4me ....

Wdrażając ImplicitNamingStrategymożesz stworzyć reguły automatycznego nazywania ograniczeń. Zauważ, że dodajesz swoją strategię nazewnictwa do metadataBuilderpodczas inicjalizacji Hibernate:

metadataBuilder.applyImplicitNamingStrategy(new MyImplicitNamingStrategy());

Działa dla @UniqueConstraint, ale nie dla @Column(unique = true), które zawsze generuje losową nazwę (np. UK_3u5h7y36qqa13y3mauc5xxayq).

Istnieje raport o błędzie, aby rozwiązać ten problem, więc jeśli możesz, zagłosuj tam, aby to zaimplementować. Tutaj: https://hibernate.atlassian.net/browse/HHH-11586

Dzięki.

MarcG
źródło