@UniqueConstraint и @Column (unique = true) в аннотации гибернации

105

В чем разница между @UniqueConstraint и @Column (unique = true) ?

Например:

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

И

@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
источник
2
Примечание. Когда я добавил Hibernate 5.4, unique=trueиндекс не добавлялся программой автоматического обновления схемы. @UniqueConstraintзаставил это появиться. Может быть ошибка.
Ondra

Ответы:

148

Как было сказано ранее, @Column(unique = true)это ярлык, UniqueConstraintкогда это только одно поле.

Из приведенного вами примера видно, что между ними есть огромная разница.

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

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

Этот код подразумевает, что оба maskи groupдолжны быть уникальными, но по отдельности. Это означает, что, например, если у вас есть запись с mask.id = 1 и вы попытаетесь вставить другую запись с mask.id = 1 , вы получите сообщение об ошибке, потому что этот столбец должен иметь уникальные значения. То же самое и для группы.

С другой стороны,

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

Подразумевается, что значения комбинации маска + группа должны быть уникальными. Это означает, что у вас может быть, например, запись с mask.id = 1 и group.id = 1 , и если вы попытаетесь вставить другую запись с mask.id = 1 и group.id = 2 , она будет вставлена успешно, а в первом случае - нет.

Если вы хотите, чтобы и маска, и группа были уникальными по отдельности и на уровне класса, вам нужно написать следующий код:

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

Это имеет тот же эффект, что и первый блок кода.

Глаубер Несполи
источник
После создания уникального ограничения могу ли я ссылаться на ограничение по имени в моем репозитории JPA, чтобы запросить его?
jDub9 09
@ jDub9 Вы не можете запросить индекс. Вы можете запросить столбцы маски и группы в одном запросе, и он будет использовать этот индекс для более быстрой обработки (если вам повезет), но вы не можете просто запросить индекс.
Далибор Филус
Но помните, что имена столбцов должны быть действительными именами в базе данных. Это должно быть mask_idи group_idпри использовании по умолчанию стратегии именования.
vitro
27

Из документации Java EE:

public abstract boolean unique

(Необязательно) Является ли свойство уникальным ключом. Это ярлык для аннотации UniqueConstraint на уровне таблицы, который полезен, когда ограничением уникального ключа является только одно поле. Это ограничение применяется в дополнение к любым ограничениям, связанным с отображением первичного ключа, и к ограничениям, указанным на уровне таблицы.

См. Документ

Вооз
источник
поэтому, когда я использую этот код: @Column (unique = true) @ManyToOne (optional = false, fetch = FetchType.EAGER) private ProductSerialMask mask; @Column (unique = true) @ManyToOne (optional = false, fetch = FetchType.EAGER) частная группа группы; У меня есть два индекса, но при использовании другого способа у меня есть один индекс, состоящий из двух столбцов?
navid_gh
22

В дополнение к ответу Вооза ....

@UniqueConstraintпозволяет назвать ограничение , а @Column(unique = true)генерирует случайное имя (например UK_3u5h7y36qqa13y3mauc5xxayq).

Иногда может быть полезно узнать, с какой таблицей связано ограничение. Например:

@Table(
   name = "product_serial_group_mask", 
   uniqueConstraints = {
      @UniqueConstraint(
          columnNames = {"mask", "group"},
          name="uk_product_serial_group_mask"
      )
   }
)
vegemite4me
источник
5

В дополнение к ответам @ Boaz и @ vegemite4me ....

Реализуя, ImplicitNamingStrategyвы можете создавать правила для автоматического именования ограничений. Обратите внимание, что вы добавляете свою стратегию именования metadataBuilderво время инициализации Hibernate:

metadataBuilder.applyImplicitNamingStrategy(new MyImplicitNamingStrategy());

Он работает @UniqueConstraint, но не для @Column(unique = true), который всегда генерирует случайное имя (например, UK_3u5h7y36qqa13y3mauc5xxayq).

Для решения этой проблемы существует отчет об ошибке, поэтому, если вы можете, проголосуйте, чтобы это было реализовано. Здесь: https://hibernate.atlassian.net/browse/HHH-11586

Спасибо.

MarcG
источник