@UniqueConstraint e @Column (unique = true) na anotação de hibernação

104

Qual é a diferença entre @UniqueConstraint e @Column (unique = true) ?

Por exemplo:

@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;
navid_gh
fonte
2
Nota: Com o Hibernate 5.4, quando adicionei unique=true, o índice não foi adicionado pelo atualizador automático do esquema. @UniqueConstraintfez parecer. Pode ser um bug.
Ondra Žižka

Respostas:

147

Como disse antes, @Column(unique = true)é um atalho paraUniqueConstraint quando é apenas um campo.

Pelo exemplo que você deu, há uma grande diferença entre os dois.

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

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

Este código implica que ambos maske groupdevem ser únicos, mas separadamente. Isso significa que se, por exemplo, você tiver um registro com mask.id = 1 e tentar inserir outro registro com mask.id = 1 , receberá um erro, porque essa coluna deve ter valores únicos. O mesmo se aplica ao grupo.

Por outro lado,

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

Implica que os valores de máscara + grupo combinados devem ser únicos. Isso significa que você pode ter, por exemplo, um registro com mask.id = 1 e group.id = 1 , e se você tentar inserir outro registro com mask.id = 1 e group.id = 2 , ele será inserido com sucesso, enquanto no primeiro caso não o faria.

Se você quiser que a máscara e o grupo sejam únicos separadamente e no nível da classe, você terá que escrever o código da seguinte forma:

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

Isso tem o mesmo efeito que o primeiro bloco de código.

Glauber Néspoli
fonte
Depois que a restrição exclusiva é criada, posso fazer referência à restrição por nome em meu Repositório JPA para consultá-la?
jDub9
@ jDub9 Você não pode consultar um índice. Você pode consultar as colunas de máscara e grupo, em uma consulta, e ele usará esse índice para processamento mais rápido (se você tiver sorte), mas você não pode simplesmente consultar um índice.
Dalibor Filus
Tenha cuidado, porém, que columnNames deve ser nomes reais no banco de dados. Deve ser mask_ide group_idse você usar a estratégia de nomenclatura padrão.
vitro
27

Da documentação do Java EE:

public abstract boolean unique

(Opcional) Se a propriedade é uma chave exclusiva. Este é um atalho para a anotação UniqueConstraint no nível da tabela e é útil quando a restrição de chave exclusiva é apenas um único campo. Essa restrição se aplica além de qualquer restrição acarretada pelo mapeamento de chave primária e às restrições especificadas no nível da tabela.

Veja doc

Boaz
fonte
então, quando eu uso este código: @Column (unique = true) @ManyToOne (optional = false, fetch = FetchType.EAGER) private ProductSerialMask mask; @Column (unique = true) @ManyToOne (opcional = false, fetch = FetchType.EAGER) Grupo privado do grupo; Tenho dois índices mas quando uso de outra forma tenho um índice que é combinação de duas colunas?
navid_gh
22

Além da resposta de Boaz ....

@UniqueConstraintpermite nomear a restrição , enquanto @Column(unique = true)gera um nome aleatório (por exemplo UK_3u5h7y36qqa13y3mauc5xxayq).

Às vezes, pode ser útil saber a qual tabela uma restrição está associada. Por exemplo:

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

Além das respostas de @ Boaz e @ vegemite4me ....

Ao implementar, ImplicitNamingStrategyvocê pode criar regras para nomear automaticamente as restrições. Observe que você adiciona sua estratégia de nomenclatura ao metadataBuilderdurante a inicialização do Hibernate:

metadataBuilder.applyImplicitNamingStrategy(new MyImplicitNamingStrategy());

Ele funciona para @UniqueConstraint, mas não para @Column(unique = true), que sempre gera um nome aleatório (por exemplo, UK_3u5h7y36qqa13y3mauc5xxayq).

Há um relatório de bug para resolver esse problema, então se você puder, vote aqui para que isso seja implementado. Aqui: https://hibernate.atlassian.net/browse/HHH-11586

Obrigado.

MarcG
fonte