Hibernate:Where insertable = false,updatable = false属于涉及外键的复合主键星座?
在Hibernate或其他ORM中实现复合主键时,在使用标识关系的复合主键星座(FK是PK的一部分)中,最多有三处将insertable = false,updatable = false:
- 进入复合PK类的@Column注解(@Embeddable类)或
- 进入实体类的关联@ContactColumn / s注释或
- 进入实体类的冗余 PK属性的@Column注解(仅限于@IdClass类)
第三个是使用@IdClass和JPA 1.0 AFAIK的唯一方法。 见http://en.wikibooks.org/wiki/Java_Persistence/Identity_and_Sequencing#Primary_Keys_through_OneToOne_Relationships 。 我会考虑只有案件1和2。
问:一般来说,将“insertable = false,updatable = false”放在哪个位置是最好的select?
关于这个问题,我遇到了Hibernate的问题。 例如,Hibernate 3.5.x会抱怨Zips表
CREATE TABLE Zips ( country_code CHAR(2), code VARCHAR(10), PRIMARY KEY (country_code, code), FOREIGN KEY (country_code) REFERENCES Countries (iso_code) )
有:
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) ...
正如你所看到的country_code列是PK和FK。 这里是它的类:
实体类:
@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; ... }
复合PK类:
@Embeddable public class ZipId implements Serializable { @Column(name = "country_code", insertable = false, updatable = false) private String countryCode; @Column(name = "code") private String code; ... }
将insertable = false,updatable = false放入实体类关联的@JoinColumn时,所有exception消失,一切正常。 但是,我不明白为什么上面的代码不应该工作。 这可能是Hibernate有这个问题。 是描述了一个Hibernate的bug,因为它似乎没有评估@Column“insertable = false,updatable = false”?
从本质上讲,什么是标准JPA方式,最佳实践或偏好何处放置“insertable = false,updatable = false”?
让我一步一步回答。
1.你什么时候需要`insertable = false,updatable = false`?
让我们看看下面的映射,
public class zip { @ManyToOne @JoinColumn(name = "country_code", referencedColumnName = "iso_code") private Country country = null @Column(name = "country_code") private String countryCode; }
这里我们使用两个不同的属性来引用表中的同一列。 在下面的代码中,
Zip z = new zip(); z.setCountry(getCountry("US")); x.setCountryCode("IN"); saveZip(z);
冬眠会在这里做什么?
为了防止这种不一致,hibernate要求你指定关系的更新点。 这意味着你可以引用表中的同一列n
次,但只有其中一个可以用来更新,而其他的只能被读取 。
2.为什么hibernate抱怨你的映射?
在您的Zip
类中,您指的是embedded式id类ZipId
, ZipId
包含国家/地区代码。 正如在上面的情况下,你现在可以从两个地方更新counry_code
列。 因此,hibernate给出的错误是适当的。
3.如何解决你的情况?
不,理想情况下,您希望ZipId
类生成id,因此您不应将insertable = false, updatable = false
ZipId
insertable = false, updatable = false
到ZipId
内的countryCode。 所以修正如下修改你的zip
类中的country
映射如下,
@ManyToOne @JoinColumn(name = "country_code", referencedColumnName = "iso_code", insertable = false, updatable = false) private Country country;
希望这有助于你的理解。
你也可以使用@PrimaryKeyJoinColumn
注解来解决这个问题。 PrimaryKeyJoinColumn注释指定用作外键的主键列以连接到另一个表。
PrimaryKeyJoinColumn注解用于将JOINED映射策略中的实体子类的主表连接到其超类的主表; 它在SecondaryTable注释中用于将辅助表连接到主表; 并且可以用在OneToOne映射中,其中引用实体的主键被用作被引用实体的外键。 如果在JOINED映射策略中没有为子类指定PrimaryKeyJoinColumn注释,则假定外键列与超类主表的主键列具有相同的名称。