@UniqueConstraint y @Column (único = verdadero) en la anotación de hibernación

104

¿Cuál es la diferencia entre @UniqueConstraint y @Column (único = verdadero) ?

Por ejemplo:

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

Y

@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
fuente
2
Nota: Con Hibernate 5.4, cuando agregué unique=true, el actualizador automático de esquemas no agregó el índice. @UniqueConstraintlo hizo aparecer. Podría ser un error.
Ondra Žižka

Respuestas:

147

Como se dijo antes, @Column(unique = true)es un atajo para UniqueConstraintcuando es un solo campo.

Por el ejemplo que dio, hay una gran diferencia entre ambos.

@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 masky grouptienen que ser únicos, pero por separado. Eso significa que si, por ejemplo, tiene un registro con mask.id = 1 e intenta insertar otro registro con mask.id = 1 , obtendrá un error, porque esa columna debe tener valores únicos. Lo mismo se aplica al grupo.

Por otra parte,

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

Implica que los valores de máscara + grupo combinados deben ser únicos. Eso significa que puede tener, por ejemplo, un registro con mask.id = 1 y group.id = 1 , y si intenta insertar otro registro con mask.id = 1 y group.id = 2 , se insertará con éxito, mientras que en el primer caso no lo haría.

Si desea que tanto la máscara como el grupo sean únicos por separado y para eso a nivel de clase, tendrá que escribir el código de la siguiente manera:

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

Esto tiene el mismo efecto que el primer bloque de código.

Glauber Néspoli
fuente
Una vez que se crea la restricción única, ¿puedo hacer referencia a la restricción por nombre en mi repositorio JPA para consultar sobre eso?
jDub9
@ jDub9 No puede consultar un índice. Puede consultar la máscara y las columnas de grupo, en una consulta, y usará ese índice para un procesamiento más rápido (si tiene suerte), pero no puede simplemente consultar un índice.
Dalibor Filus
Sin embargo, tenga en cuenta que columnNames debe ser nombres reales en la base de datos. Debería serlo mask_idy group_idsi usa la estrategia de nomenclatura predeterminada.
vitro
27

De la documentación de Java EE:

public abstract boolean unique

(Opcional) Si la propiedad es una clave única. Este es un atajo para la anotación UniqueConstraint en el nivel de tabla y es útil cuando la restricción de clave única es solo un campo. Esta restricción se aplica además de cualquier restricción que conlleve la asignación de clave primaria y a las restricciones especificadas en el nivel de la tabla.

Ver documento

Booz
fuente
así que cuando uso este código: @Column (único = verdadero) @ManyToOne (opcional = falso, fetch = FetchType.EAGER) máscara de ProductSerialMask privada; @Column (único = verdadero) @ManyToOne (opcional = falso, fetch = FetchType.EAGER) grupo de grupo privado; Tengo dos índices, pero cuando lo uso de otra manera, ¿tengo un índice que es una combinación de dos columnas?
navid_gh
22

Además de la respuesta de Booz ...

@UniqueConstraintle permite nombrar la restricción , mientras @Column(unique = true)genera un nombre aleatorio (por ejemplo UK_3u5h7y36qqa13y3mauc5xxayq).

A veces puede resultar útil saber con qué tabla está asociada una restricción. P.ej:

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

Además de las respuestas de @ Boaz y @ vegemite4me ...

Al implementarlo ImplicitNamingStrategy, puede crear reglas para nombrar automáticamente las restricciones. Tenga en cuenta que agrega su estrategia de nomenclatura metadataBuilderdurante la inicialización de Hibernate:

metadataBuilder.applyImplicitNamingStrategy(new MyImplicitNamingStrategy());

Funciona para @UniqueConstraint, pero no para @Column(unique = true), que siempre genera un nombre aleatorio (por ejemplo, UK_3u5h7y36qqa13y3mauc5xxayq).

Hay un informe de error para resolver este problema, así que si puede, vote allí para implementarlo. Aquí: https://hibernate.atlassian.net/browse/HHH-11586

Gracias.

MarcG
fuente