本讨论假设在 persistence.xml 中为 hibernate.hbm2ddl.auto 分配了诸如“update”之类的属性,以使 Hibernate 能够建立一对一关系并在拥有实体中为非拥有实体创建外键,以及对应表中的外键标识列。但是,只有在创建表时建立了关系,此过程才会成功。将@JoinColumn 和@OneToOne(mappedBy) 添加到现有实体将导致Hibernate 抱怨FK 列在拥有表中不存在。所以在实现包含实时数据的表之间的关系时,需要手动添加FK列。然后,Hibernate 将能够使用像 FKg6wt3d1u6o13gdc1hj36ad1ot 这样的奇怪名称来建立 FK 约束。
所涉及的细微差别通过一个稍微更详细的示例来说明。考虑一个数据库,其中实体联系人将是连接 OneToOne 的各种表(员工、客户、供应商等)的公共组件。作为初步考虑,虽然 OneToOne 关系可能是双向的,但它在 Hibernate 中的实现要求为公共实体分配非拥有名称,以便在每个拥有实体的表中创建 FK。反过来实现 OneToOne 将导致 Hibernate 在 NON-owning 类中查找外键,并在找不到时抛出错误。(去过也做过。)
@Entity // common, non-owning entity
public class Contact implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Integer id;
@Column(name="fn")
private String firstName;
@Column(name="ln")
private String lastName;
// "person" is the Contact entity as declared in Director
@OneToOne(optional=false, mappedBy = "person")
private Director director;
// GETTERS & SETTERS
和
@Entity // owning entity
public class Director implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id", updatable = false, nullable = false)
private Integer id;
@Column(name="title")
private String title;
@OneToOne
@JoinColumn
private Contact person;
public Integer getId() {
return id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Contact getPerson() {
return person;
}
public void setPerson(Contact person) {
this.person = person;
}
假设 Director 中存在 FK 列,代码生成:
alter table Director
add constraint FKg6wt3d1u6o13gdc1hj36ad1ot
foreign key (person_id)
references Contact (id)
Hibernate 分配给 Director 中的 Contact 实体的 FK 名称的派生有点模糊。它是分配给拥有实体(此处为人员)中的联系人实例变量的变量名 +“_”+ 实体的主键“id”的串联,从而产生 person_id。另请注意,@OneToOne(mappedBy = "person") 注释引用了相同的 Contact 实例变量。最后,Hibernate 直接访问 FK 列,而不需要 Director 类中对应的 getter 和 setter。