在上一篇,也就是Hibernate关系映射(一)中已经介绍了一对一单向外键关联,本篇介绍一对一双向外键关联
首先还是来构造一个实际应用的场景,比如实体类车辆(Car),它具有以下属性:Id,品牌(brand),车牌(lisencePlate);实体类车牌(LisencePlate),它具有以下属性:Id,号码(number),所属车辆(car)。那么车辆和车牌是一对一的关系,一辆车只能有一个车牌,一个车牌也只能属于一辆车,不允许套牌,典型的一对一关系,依然是根据PowerDesigner反向工程反向出来的表结构如图:
car这个表中有一个字段lisencePlate_id作为外键指向了lisence_plate表的主键id字段。
重点内容
看表结构,单向关联的表结构和双向关联的表结构在数据库中的表示是一致的,但是单向关联和双向关联的区别在于,双向关联,你可以用car.getLisencePlate来找到该车辆的车牌,也可以用lisencePlate.getCar来找到该车牌所属车辆,但是单向关联只能从车找到车牌,或者从车牌找到车。
下面是实体类:
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="car")
public class Car {
private Integer id;
private String brand;
private LisencePlate lisencePlate;
public Car() {
super();
}
public Car(Integer id, String brand, LisencePlate lisencePlate) {
super();
this.id = id;
this.brand = brand;
this.lisencePlate = lisencePlate;
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getBrand() {
return brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
@OneToOne
public LisencePlate getLisencePlate() {
return lisencePlate;
}
public void setLisencePlate(LisencePlate lisencePlate) {
this.lisencePlate = lisencePlate;
}
}
每一个使用到的标签的含义在上一篇介绍过了,这里不再赘述。
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;
import javax.persistence.Table;
@Entity
@Table(name="lisence_plate")
public class LisencePlate {
private Integer id;
private String number;
private Car car;
public LisencePlate() {
super();
}
public LisencePlate(Integer id, String number, Car car) {
super();
this.id = id;
this.number = number;
this.car = car;
}
@Id
@GeneratedValue
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
@OneToOne(mappedBy="lisencePlate")
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
}
注意:双向关联,那么在车牌类中也需要一个属性,所属车辆(car),设置上get和set方法后,在get方法上有这么一个标签@OneToOne(mappedBy=”lisencePlate”),@OneToOne表示车牌和车辆也是一对一的关系并且关联上车辆,mappeBy表示被谁映射,并且mappedBy应该存在于“被拥有方”,指向“拥有方”,那么指向拥有方应该指向车辆类,mappedBy=”lisencePlate”表示指向车辆类的lisencePlate属性,表示被lisencePlate属性映射,并且lisencePlate是主导。
重点内容
双向关联必须设置mappedBy
最后在hibernate.cfg.xml配置文件中设置上实体的映射就可以了
<mapping class="com.ht.entity.one2one.bi.fk.Car"/>
<mapping class="com.ht.entity.one2one.bi.fk.LisencePlate"/>
下面来看CRUD的测试,首先测试添加新数据testCreate()方法
import java.util.ArrayList;
import java.util.List;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import com.ht.entity.one2one.bi.fk.Car;
import com.ht.entity.one2one.bi.fk.LisencePlate;
public class One2OneTest2 {
private static SessionFactory sessionFactory;
@BeforeClass
public static void beforeClass() {
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
}
@AfterClass
public static void afterClass() {
sessionFactory.close();
}
@Test
public void testCreate(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Car car = new Car();
car.setBrand("Jeep Grand Cherokee");
LisencePlate lisencePlate = new LisencePlate();
lisencePlate.setNumber("云A 12345");
car.setLisencePlate(lisencePlate);
lisencePlate.setCar(car);
session.save(lisencePlate);
session.save(car);
session.getTransaction().commit();
}
结果如图:
Hibernate:
insert
into
lisence_plate
(number)
values
(?)
Hibernate:
insert
into
car
(brand, lisencePlate_id)
values
(?, ?)
接下来测试数据读取,testRead()方法
@Test
public void testRead(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Car car = (Car) session.load(Car.class, 1);
System.out.println(car.getBrand()+" "+car.getLisencePlate().getNumber());
LisencePlate lisencePlate = (LisencePlate) session.load(LisencePlate.class, 1);
System.out.println(lisencePlate.getNumber()+" "+lisencePlate.getCar().getBrand());
session.getTransaction().commit();
}
这里就体现了双向关联和单向关联的区别,双向关联可以从车辆找到车牌信息,也可以从车牌找到所属车辆的信息。
Hibernate:
select
car0_.id as id2_1_,
car0_.lisencePlate_id as lisenceP3_2_1_,
car0_.brand as brand2_1_,
lisencepla1_.id as id3_0_,
lisencepla1_.number as number3_0_
from
car car0_
left outer join
lisence_plate lisencepla1_
on car0_.lisencePlate_id=lisencepla1_.id
where
car0_.id=?
Hibernate:
select
car0_.id as id2_1_,
car0_.lisencePlate_id as lisenceP3_2_1_,
car0_.brand as brand2_1_,
lisencepla1_.id as id3_0_,
lisencepla1_.number as number3_0_
from
car car0_
left outer join
lisence_plate lisencepla1_
on car0_.lisencePlate_id=lisencepla1_.id
where
car0_.lisencePlate_id=?
Jeep Grand Cherokee 云A 12345
云A 12345 Jeep Grand Cherokee
下面测试修改数据,testUpdate()方法
@Test
public void testUpdate(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Car car = (Car) session.load(Car.class, 1);
car.setBrand("Jeep大切诺基");
LisencePlate lisencePlate = (LisencePlate) session.load(LisencePlate.class, 1);
lisencePlate.setNumber("云A 66666");
session.saveOrUpdate(car);
session.saveOrUpdate(lisencePlate);
session.getTransaction().commit();
}
结果如下:
Hibernate:
update
lisence_plate
set
number=?
where
id=?
Hibernate:
update
car
set
lisencePlate_id=?,
brand=?
where
id=?
最后是删除操作,testDelete()方法,一样的,如果只是删除车牌,那么就要先解除该车牌和所属车辆之间的约束
@Test
public void testDelete(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Car car = (Car) session.load(Car.class, 1);
LisencePlate lisencePlate = (LisencePlate) session.load(LisencePlate.class, 1);
car.setLisencePlate(null);
session.delete(lisencePlate);
session.getTransaction().commit();
}
结果如下:
Hibernate:
update
car
set
lisencePlate_id=?,
brand=?
where
id=?
Hibernate:
delete
from
lisence_plate
where
id=?
希望对你所有帮助,下一篇介绍多对一的单向关联
[上一篇 Hibernate关系映射(一)一对一单向外键关联@OneToOne Annotation方式](http://blog.csdn.net/murcielagoan/article/details/43954727)