Hibernate的关联映射(7)-双向1-1关联

本文介绍了一对一关联关系在实体类间的两种映射方式:基于外键的映射和使用连接表的映射。包括如何设置@OneToOne、@JoinColumn、@JoinTable等注解。

双向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>
从上面的两个关联实体的注解来看,他们双方所使用的注解是对等的,他们双方映射的表名是相同的,映射连接表中的外键列也是相互对应的,因此这两个实体都可用于控制关系,并且双方的地位是绝对平等的;

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值