Hibernation: Où est-ce que insertable = false, updable = false appartiennent dans des constellations de clés primaires composées impliquant des clés étrangères?
lors de la mise en œuvre des clés primaires composites dans les Ormes Hibernés ou autres, il y a jusqu'à trois endroits où placer l'insertable = false, updable = false dans les constellations de clés primaires composites qui utilisent des relations d'identification (FKs qui font partie de la PK):
- dans l'annotation composite de la classe PK' @Column (@Embeddable classes seulement) ou
- dans la classe entity' association @JoinColumn/s annotation ou
- dans la classe "entity" redondant annotation @Column de la propriété PK (@IdClass classes seulement)
la troisième est la seule façon de faire avec @IdClass et JPA 1.0 AFAIK. Voir http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Primary_Keys_through_OneToOne_Relationships. Je n'examinerai que les cas 1. et 2.
Q: De quelle façon est-il préférable de mettre "insertable = false, updable = false" en général?
j'ai j'ai eu des problèmes avec hibernation à ce sujet. Par exemple, hibernation 3.5.x se plaindra de la table Zips
CREATE TABLE Zips
(
country_code CHAR(2),
code VARCHAR(10),
PRIMARY KEY (country_code, code),
FOREIGN KEY (country_code) REFERENCES Countries (iso_code)
)
avec:
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)
...
comme vous pouvez le voir, la colonne country_code est à la fois PK et FK. Ici sont ses classes:
classe d'Entité:
@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;
...
}
Composite PK class:
@Embeddable
public class ZipId implements Serializable
{
@Column(name = "country_code", insertable = false, updatable = false)
private String countryCode;
@Column(name = "code")
private String code;
...
}
lors de la mise en place de l'insertable = false, updable = false dans l'association de classe entity @JoinColumn toutes les exceptions disparaissent et tout ce beau travail. Cependant, je ne vois pas pourquoi le code ci-dessus ne doivent pas travailler. C'est peut-être hiberné qui a des problèmes avec ça. Est-ce que le décrit est un bug D'hibernation, car il ne semble pas évaluer @Column "insertable = false, updable = false"?
essentiellement, Quelle est la méthode standard JPA, la meilleure pratique, ou préférence où mettre "insertable = false, updable = false"?
2 réponses
laissez-moi répondre étape par étape.
1. Quand avez-vous besoin de`insertable = false, updable = false'?
regardons la cartographie ci-dessous,
public class Zip {
@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code")
private Country country = null
@Column(name = "country_code")
private String countryCode;
}
ici, nous nous référons à la même colonne dans le tableau en utilisant deux propriétés différentes. Dans le code ci-dessous,
Zip z = new Zip();
z.setCountry(getCountry("US"));
z.setCountryCode("IN");
saveZip(z);
Que fait hiberné ici??
pour éviter ce genre d'incohérence, hibernate vous demande de spécifier le point de mise à jour des relations. Qui signifie vous pouvez vous référer à la même colonne dans la table n
nombre de fois mais un seul d'entre eux peut être utilisé pour mettre à jour et tous les autres seront lus seulement.
2. Pourquoi les hibernés se plaignent - ils de votre carte?
Dans votre Zip
classe que vous faites référence à l'Embedded id de classe ZipId
qui contient à nouveau le code de pays. Comme dans le scénario ci-dessus, vous avez maintenant la possibilité de mettre à jour le counry_code
colonne à deux endroits. D'où l'erreur donnée par l'hibernation est convenable.
3. Comment résoudre le problème dans votre cas?
Non. Idéalement vous voulez votre ZipId
classe pour générer l'id, donc vous ne devez pas ajouter insertable = false, updatable = false
au code du pays à l'intérieur du ZipId
. Ainsi, le correctif est comme ci-dessous modifier le country
cartographie dans votre Zip
classe comme ci-dessous,
@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code",
insertable = false, updatable = false)
private Country country;
J'espère que cela vous aidera à comprendre.
Vous pouvez également résoudre ce problème en utilisant @PrimaryKeyJoinColumn
annotation . L'annotation PrimaryKeyJoinColumn spécifie une colonne de clé primaire qui est utilisée comme clé étrangère pour se joindre à une autre table.
l'annotation PrimaryKeyJoinColumn est utilisée pour joindre la table primaire d'une sous-classe d'entité dans la stratégie de mappage jointe à la table primaire de sa superclasse; elle est utilisée dans une annotation SecondaryTable pour joindre une table secondaire à une table primaire; et elle peut être utilisée dans une OneToOne cartographie dans lequel la clé primaire de l'entité de référence est utilisé comme une clé étrangère de l'entité référencée. Si aucune annotation de colonne primaire N'est spécifiée pour une sous-classe dans la stratégie de mappage jointe, les colonnes de clés étrangères sont supposées avoir les mêmes noms que les colonnes de clés primaires du tableau primaire de la superclasse.