@UniqueConstraint et @Column (unique = true) dans l'annotation d'hibernation

104

Quelle est la différence entre @UniqueConstraint et @Column (unique = true) ?

Par exemple:

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

Et

@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
la source
2
Remarque: Avec Hibernate 5.4, lorsque j'ai ajouté unique=true, l'index n'a pas été ajouté par le programme de mise à jour automatique du schéma. @UniqueConstraintl'a fait apparaître. Cela pourrait être un bug.
Ondra Žižka

Réponses:

147

Comme dit précédemment, @Column(unique = true)est un raccourci vers UniqueConstraintquand il ne s'agit que d'un seul champ.

D'après l'exemple que vous avez donné, il y a une énorme différence entre les deux.

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

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

Ce code implique que les deux masket groupdoivent être uniques, mais séparément. Cela signifie que si, par exemple, vous avez un enregistrement avec un mask.id = 1 et essayez d'insérer un autre enregistrement avec mask.id = 1 , vous obtiendrez une erreur, car cette colonne doit avoir des valeurs uniques. La même chose vaut pour le groupe.

D'autre part,

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

Implique que les valeurs de masque + groupe combinées doivent être uniques. Cela signifie que vous pouvez avoir, par exemple, un enregistrement avec mask.id = 1 et group.id = 1 , et si vous essayez d'insérer un autre enregistrement avec mask.id = 1 et group.id = 2 , il sera inséré avec succès, alors que dans le premier cas non.

Si vous souhaitez que le masque et le groupe soient uniques séparément et au niveau de la classe, vous devez écrire le code comme suit:

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

Cela a le même effet que le premier bloc de code.

Glauber Néspoli
la source
Une fois la contrainte unique créée, puis-je référencer la contrainte par son nom dans mon référentiel JPA pour interroger là-dessus?
jDub9
@ jDub9 Vous ne pouvez pas interroger un index. Vous pouvez interroger le masque et les colonnes de groupe, en une seule requête, et il utilisera cet index pour un traitement plus rapide (si vous avez de la chance), mais vous ne pouvez pas simplement interroger un index.
Dalibor Filus
Attention cependant que columnNames doit être des noms réels dans la base de données. Il devrait l'être mask_idet group_idsi vous utilisez la stratégie de dénomination par défaut.
vitro le
27

À partir de la documentation Java EE:

public abstract boolean unique

(Facultatif) Indique si la propriété est une clé unique. Il s'agit d'un raccourci pour l'annotation UniqueConstraint au niveau de la table et est utile lorsque la contrainte de clé unique n'est qu'un seul champ. Cette contrainte s'applique en plus de toute contrainte induite par le mappage de clé primaire et aux contraintes spécifiées au niveau de la table.

Voir doc

Boaz
la source
donc quand j'utilise ce code: @Column (unique = true) @ManyToOne (optional = false, fetch = FetchType.EAGER) private ProductSerialMask mask; @Column (unique = true) @ManyToOne (facultatif = false, fetch = FetchType.EAGER) groupe de groupes privé; J'ai deux index, mais lorsque j'utilise une autre manière, j'ai un index qui combine deux colonnes?
navid_gh
22

En plus de la réponse de Boaz ...

@UniqueConstraintvous permet de nommer la contrainte , tandis que @Column(unique = true)génère un nom aléatoire (par exemple UK_3u5h7y36qqa13y3mauc5xxayq).

Parfois, il peut être utile de savoir à quelle table une contrainte est associée. Par exemple:

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

En plus des réponses de @ Boaz et @ vegemite4me ....

En mettant en œuvre, ImplicitNamingStrategyvous pouvez créer des règles pour nommer automatiquement les contraintes. Notez que vous ajoutez votre stratégie de dénomination au metadataBuilderlors de l'initialisation d'Hibernate:

metadataBuilder.applyImplicitNamingStrategy(new MyImplicitNamingStrategy());

Cela fonctionne pour @UniqueConstraint, mais pas pour @Column(unique = true), qui génère toujours un nom aléatoire (par exemple UK_3u5h7y36qqa13y3mauc5xxayq).

Il existe un rapport de bogue pour résoudre ce problème, donc si vous le pouvez, veuillez voter pour que cela soit implémenté. Ici: https://hibernate.atlassian.net/browse/HHH-11586

Merci.

MarcG
la source