java - primary - Hibernate: ¿dónde insertable=false, updatable=false pertenece a las constelaciones de clave primaria compuestas que implican claves externas?
spring data jpa composite primary key (2)
Déjame responder paso a paso.
1. ¿Cuándo necesitas `insertable = false, updatable = false`?
Veamos el mapeo a continuación,
public class Zip {
@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code")
private Country country = null
@Column(name = "country_code")
private String countryCode;
}
Aquí nos referimos a la misma columna en la tabla que usa dos propiedades diferentes. En el siguiente código,
Zip z = new Zip();
z.setCountry(getCountry("US"));
z.setCountryCode("IN");
saveZip(z);
¿Qué va a hibernar aquí?
Para evitar este tipo de incoherencia, hibernate te pide que especifiques el punto de actualización de las relaciones. Lo que significa que puede referirse a la misma columna en la tabla n
número de veces, pero solo uno de ellos se puede usar para actualizar y todos los demás serán de solo lectura .
2. ¿Por qué hibernate se queja de su mapeo?
En su clase Zip
, se refiere al ZipId
clase de identificación ZipId
que nuevamente contiene el código de país. Como en el caso anterior, ahora tiene la posibilidad de actualizar la columna counry_code
de dos lugares. Por lo tanto, el error dado por hibernar es correcto.
3. ¿Cómo arreglarlo en tu caso?
No. Lo ideal es que desee que su clase ZipId
genere la identificación, por lo que no debe agregar insertable = false, updatable = false
al ZipId
dentro de ZipId
. Así que la solución es la siguiente, modifique la asignación de country
en su clase Zip
como se muestra a continuación,
@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code",
insertable = false, updatable = false)
private Country country;
Espero que esto ayude a tu comprensión.
Al implementar claves primarias compuestas en Hibernate u otros ORM hay hasta tres lugares donde poner el insertable = falso, actualizable = falso en constelaciones de claves primarias compuestas que usan relaciones de identificación (FK que son parte del PK):
- En la clase compuesta PK ''@Column annotation (@Embeddable classes only) o
- En la asociación de clase de entidad @ JoinColumn / s anotación o
- En la anotación @Column de la propiedad PK redundante de la clase de entidad (solo clases @IdClass)
El tercero es la única forma de hacer con @IdClass y JPA 1.0 AFAIK. Ver http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Primary_Keys_through_OneToOne_Relationships . Consideraré solo los casos 1. y 2.
P: ¿Cuál es el lugar preferido para poner "insertable = false, updatable = false" en general?
He tenido problemas con Hibernate con respecto a esta pregunta. Por ejemplo, Hibernate 3.5.x se quejará de la tabla Zips
CREATE TABLE Zips
(
country_code CHAR(2),
code VARCHAR(10),
PRIMARY KEY (country_code, code),
FOREIGN KEY (country_code) REFERENCES Countries (iso_code)
)
con:
org.hibernate.MappingException: Repeated column in mapping for entity: com.kawoolutions.bbstats.model.Zip column: country_code (should be mapped with insert="false" update="false")
org.hibernate.mapping.PersistentClass.checkColumnDuplication(PersistentClass.java:676)
org.hibernate.mapping.PersistentClass.checkPropertyColumnDuplication(PersistentClass.java:698)
...
Como puede ver, la columna country_code es PK y FK. Estas son sus clases:
Clase de entidad:
@Entity
@Table(name = "Zips")
public class Zip implements Serializable
{
@EmbeddedId
private ZipId id;
@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code")
private Country country = null;
...
}
Clase compuesta de PK:
@Embeddable
public class ZipId implements Serializable
{
@Column(name = "country_code", insertable = false, updatable = false)
private String countryCode;
@Column(name = "code")
private String code;
...
}
Al poner insertable = false, updatable = false en @JoinColumn de la asociación de clases de entidad, todas las excepciones desaparecen y todo funciona bien. Sin embargo, no veo por qué el código anterior no debería estar funcionando. Podría ser Hibernate teniendo problemas con esto. ¿Es el error descrito de Hibernate, ya que no parece evaluar @Column "insertable = false, updatable = false"?
En esencia, ¿cuál es la forma estándar de JPA, la mejor práctica o preferencia donde poner "insertable = falso, actualizable = falso"?
También puede resolver este problema utilizando la anotación @PrimaryKeyJoinColumn
. La anotación PrimaryKeyJoinColumn especifica una columna de clave principal que se utiliza como clave externa para unirse a otra tabla.
La anotación PrimaryKeyJoinColumn se usa para unir la tabla primaria de una subclase de entidad en la estrategia de asignación JOINED a la tabla primaria de su superclase; se usa dentro de una anotación de tabla secundaria para unir una tabla secundaria a una tabla primaria; y puede usarse en un mapeo de OneToOne en el que la clave primaria de la entidad de referencia se usa como una clave externa para la entidad a la que se hace referencia. Si no se especifica una anotación PrimaryKeyJoinColumn para una subclase en la estrategia de asignación JOINED, se supone que las columnas de clave externa tienen los mismos nombres que las columnas de clave principal de la tabla principal de la superclase.