Hibernate的关联映射(7)-双向1-1关联
双向1-1关联
双向1-1关联需要修改两端的持久化代码,让两个持久化类都增加引用关联实体的属性,并为该属性提供setter和getter方法;
-————————————————————————————————————————————————————————————————————————————————————-
1>基于外键的双向1-1关联1
对于双向1-1关联而言,两端都需要使用@OneToOne注解进行映射;
对于基于外键的双向1-1关联,外键可以存放在任意一端,存放外键的一端,需要增加@joinColumn注解来映射外键列,与前面介绍相同的是,还应该为@JoinColumn注解增加uniique=true属性来表示该实体实际上是1的一端;
对于1-1的关联关系,两个实体原本处于平等状态,但当选择任意一端来增加外键后,(增加@JoinColumn注解的实体端),该表即变成从表,而另一个表则成为主表;
对于双向1-1关联的主表对应的实体,也不应该控制关联关系,(否则会导致生成额外的update语句,从而引起性能下降),因此主表对应的实体中使用@OneToOne注解时,应该增加@mappedBy属性,该属性用于表明该实体不管理关联关系,这一端对应的数据表将作为主表使用,不能使用@JoinColumn映射外键列;
下面是双向1-1关联的主表一端,使用@OneToOne时增加了mappedBy属性,没有使用@JoinColumn注解修饰代表关联实体的属性:
<span style="font-size:18px;">package com.anlw.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "person_inf")
public class Person {
// 标识属性
@Id
@Column(name = "person_id12")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private int age;
// 定义该Person实体所有关联的Address实体
@OneToOne(targetEntity = Address.class,mappedBy="person")
private Address address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}</span>
上面注解@OneToOne映射指定了mappedBy属性,表明该Perosn实体不再控制关联关系;
下面是双向1-1关联从表的一端,使用@OneToOne时不指定mappedBy属性,需要使用@JoinColumn注解修饰代表关联实体的属性,用于显式定义外键列;
<span style="font-size:18px;">package com.anlw.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "address_inf")
public class Address {
// 标识属性
@Id
@Column(name = "address_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int addressId;
// 定义地址详细的成员变量
private String addressDetail;
// 定义该Address实体关联的Person实体
@OneToOne(targetEntity = Person.class)
// 用于映射person_id外键列,参照person_inf表的person_id列
// 指定了unique=true表明是1-1关联
@JoinColumn(name = "person_id", referencedColumnName = "person_id12", unique = true)
private Person person;
public int getAddressId() {
return addressId;
}
public void setAddressId(int addressId) {
this.addressId = addressId;
}
public String getAddressDetail() {
return addressDetail;
}
public void setAddressDetail(String addressDetail) {
this.addressDetail = addressDetail;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
</span>
上面的@JoinColumn注解显式的映射了底层的外键列,并指定unique=true,这代表了1-1关联;
上面的映射策略可以互换,即让Person端存放外键,使用@JoinColumn注解映射关联属性,但Address端则使用@OneToOne时增加mappedBy属性,但不要两端都使用相同的注解进行映射;
-————————————————————————————————————————————————————————————————————————————————————-
2>有连接表的双向1-1关联
采用连接表的双向1-1关联是相当罕见的情形,映射相当复杂,数据模型繁琐,通常不推荐使用这种策略;
有连接表的双向1-1关联需要在两端分别使用@OneToOne修饰代表关联实体的属性,并在两端都使用@JoinTable显式的映射连接表,在映射连接表时,两端指定的连接表的表名应该相同,而且两端使用@JoinTable时指定的外键列的列名也是相互对应的;
需要说明的是,如果程序希望某一端放弃控制关联关系,则可在这一端的@OneToOne注解中指定mappedBy属性,这一端就无须也不能使用@JoinTable映射连接表了,由于此时是1-1关联,因此使用@JoinTable注解时指定的@JoinColumn都需要增加unique=true;
下面的示例让Person实体类与Address实体类保留双向1-1关联关系,而且双方都能控制关联关系,因此程序需要在两端分别使用@ObeToOne,@JoinTable映射连接表;
下面是双向1-1关联的Person实体类的代码,程序使用了@JoinTable和@OneToOne修饰代表关联实体的属性:
<span style="font-size:18px;">package com.anlw.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "person_inf")
public class Person {
// 标识属性
@Id
@Column(name = "person_id12")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private int age;
// 定义该Person实体所有关联的Address实体
@OneToOne(targetEntity = Address.class)
//映射底层连接表,表明为p_a
@JoinTable(name="p_a",
//映射连接表的外键列,增加unique=true表明是1-1关联
joinColumns=@JoinColumn(name="person_id"
,referencedColumnName="person_id12",unique=true),
//映射连接表的外键列,增加unique=true表明是1-1关联
inverseJoinColumns=@JoinColumn(name="address_id"
,referencedColumnName="address_id",unique=true))
private Address address;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}</span>
下面是双向1-1关联的Address实体类代码,程序通常使用@JoinTable和@OneToOne修饰代表关联实体的属性:
<span style="font-size:18px;">package com.anlw.entity;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name = "address_inf")
public class Address {
// 标识属性
@Id
@Column(name = "address_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int addressId;
// 定义地址详细的成员变量
private String addressDetail;
// 定义该Address实体关联的Person实体
@OneToOne(targetEntity = Person.class)
// 映射底层连接表,表明为p_a
@JoinTable(name = "p_a",
// 映射连接表的外键列,增加unique=true表明是1-1关联
joinColumns = @JoinColumn(name = "address_id", referencedColumnName = "address_id", unique = true),
// 映射连接表的外键列,增加unique=true表明是1-1关联
inverseJoinColumns = @JoinColumn(name = "person_id", referencedColumnName = "person_id12", unique = true))
private Person person;
public Address(){}
public int getAddressId() {
return addressId;
}
public void setAddressId(int addressId) {
this.addressId = addressId;
}
public String getAddressDetail() {
return addressDetail;
}
public void setAddressDetail(String addressDetail) {
this.addressDetail = addressDetail;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
}
</span>
从上面的两个关联实体的注解来看,他们双方所使用的注解是对等的,他们双方映射的表名是相同的,映射连接表中的外键列也是相互对应的,因此这两个实体都可用于控制关系,并且双方的地位是绝对平等的;
还没有评论,来说两句吧...