休眠:可插入 = false,可更新 = false 在涉及外键的复合主键星座中属于何处?

在 Hibernate 或其他 ORM 中实现复合主键时,最多有三个位置可以将可插入 = false,可更新 = false 放在使用识别关系的复合主键星座(作为 PK 一部分的 FK)中:

  1. 进入复合 PK 类的@Column注释(仅限@Embeddable类)或
  2. 进入实体类的关联@JoinColumn/s 注释或
  3. 进入实体类的冗余 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.

问:通常哪种方式放置“可插入 = 假,可更新 = 假”?

我在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;
...
}

将可插入 = false,可更新 = false 放入实体类关联的@JoinColumn所有异常都将消失,一切正常。但是,我不明白为什么上面的代码不应该工作。可能是Hibernate有问题。所描述的Hibernate错误,因为它似乎没有评估@Column“可插入=假,可更新=假”?

从本质上讲,标准的JPA方式,最佳实践或首选项在哪里放置“可插入=假,可更新=假”?


答案 1

让我一步一步地回答。

1. 什么时候需要'可插入=假,可更新=假'?

让我们看一下下面的映射,

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"));
z.setCountryCode("IN");

saveZip(z);

冬眠会在这里做什么??

为了防止这些不一致,Hibernate 要求您指定关系的更新点。这意味着您可以多次引用表中的同一列但其中只有一列可用于更新,所有其他列都将是只读的

2. 为什么Hibernate抱怨你的映射?

在您的课程中,您引用的是再次包含国家/地区代码的嵌入式 ID 类。与上面的场景一样,现在您可以从两个位置更新列。因此,Hibernate给出的错误是正确的。ZipZipIdcountry_code

3.如何解决您的情况?

不。理想情况下,您希望您的类生成 id,因此您不应添加到 .因此,修复如下,修改类中的映射,如下所示,ZipIdinsertable = false, updatable = falseZipIdcountryZip

@ManyToOne
@JoinColumn(name = "country_code", referencedColumnName = "iso_code",
insertable =  false, updatable = false)
private Country country;

希望这有助于您的理解。


答案 2

您也可以通过使用 注释 来解决此问题。PrimaryKeyJoinColumn 批注指定一个主键列,该列用作外键以联接到另一个表。@PrimaryKeyJoinColumn

PrimaryKeyJoinColumn 注释用于将 JOINED 映射策略中实体子类的主表连接到其超类的主表;它在辅助表注释中使用,以将辅助表连接到主表;它可以在一对一映射中使用,其中引用实体的主键用作被引用实体的外键。如果没有为 JOINED 映射策略中的子类指定 PrimaryKeyJoinColumn 批注,则假定外键列与超类的主表的主键列具有相同的名称。


推荐