34

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

  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。

问:通常将“insertable = false,updatable = false”放在哪个位置的首选?

关于这个问题,我遇到了 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 时,所有异常都会消失,一切正常。但是,我不明白为什么上面的代码不应该工作。可能是 Hibernate 有这个问题。所描述的是否是 Hibernate 错误,因为它似乎没有评估 @Column “insertable = false, updatable = false”?

从本质上讲,标准 JPA 方式、最佳实践或将“可插入 = 假,可更新 = 假”放在哪里的偏好是什么?

4

2 回答 2

82

让我一步一步回答。

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

saveZip(z);

Hibernate 会在这里做什么?

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

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

在您的Zip课程中,您指的ZipId是再次包含国家代码的 Embedded id 类。与上述场景一样,现在您可以country_code从两个位置更新列。因此,Hibernate 给出的错误是正确的。

3.如何解决您的情况?

不。理想情况下,您希望您的ZipId班级生成 id,因此您不应该将insertable = false, updatable = falsecountryCode 添加到ZipId. 所以修复如下修改你的类中的country映射,如下所示,Zip

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

希望这有助于您的理解。

于 2012-02-25T08:19:11.147 回答
0

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

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

于 2015-02-20T06:59:44.973 回答