一对一关联映射在实际生活中是比较常见的,如人与身份证的关系,通过人这个对象可以找到身份证相关的信
息,也可以通过身份证这个对象找到人相关的信息。
有两种策略可以实现一对一的关联映射:
主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来
维护它们之间的关系,仅通过表的主键来关联;
唯一外键关联:外键关联,本来是用于多对一的配置,但是如果加上唯一的限制之后,也可以用来表示一对一关
联关系。
我们先来假设一个场景,从Person中能看到IdCard,也就是把idCard数据表中的主键拿过来当做person表的主
键,单向一对一主键关联映射的实现就是它们的主键相等。一对一关联映射是通过在一方(Person)的对象关系配置
文件加入
如下图所示:
下面我们来实现:
Person实体类:
package com.demo.domain;
public class Person {
private int id;
private String name;
//在一方添加另一方的引用
private IdCard idCard;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
@Override
public String toString() {
return "Person [id=" + id + ", name=" + name + ", idCard=" + idCard + "]";
}
}
Person对象关系映射配置文件:
idCard
IdCard实体类:
package com.demo.domain;
public class IdCard {
private int id;
private String cardNo;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
@Override
public String toString() {
return "IdCard [id=" + id + ", cardNo=" + cardNo + "]";
}
}
IdCard对象关系映射配置文件:
测试类代码:
package com.demo.test;
import org.hibernate.Session;
import com.demo.domain.HibernateUtils;
import com.demo.domain.IdCard;
import com.demo.domain.Person;
import junit.framework.TestCase;
/**
* 单向一对一关联映射(Person-->IdCard)
* @author Administrator
* @date 2016年12月8日
*/
public class One2OneTest extends TestCase {
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNo("1111111");
Person person = new Person();
person.setName("张三");
//建立单向一对一主键映射关联
person.setIdCard(idCard);
//没有抛出TransientObjectException
//是由一对一关联映射的特性决定的,它必须先保存关联对象IdCard
//这样它采用foreign映射策略才能取得关联对象的标识
//也就是它默认了cascade属性
session.save(person);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNo("2222222");
Person person = new Person();
person.setName("李四");
//建立单向一对一主键映射关联
person.setIdCard(idCard);
//只能将IdCard保存,不能将Person保存
//因为关系的维护端在Person端,IdCard不知道Person的存在
session.save(idCard);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
public void testLoad() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Person person = (Person)session.load(Person.class, 1);
System.out.println("person.name=" + person.getName());
System.out.println("person.cardNo=" + person.getIdCard().getCardNo());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
}
testSave1()方法:
控制台输出:
数据库显示:
testSave2()方法:控制台输出:
数据库显示:
tesLoad()方法:控制台输出:
我们先来假设一个场景,双向一对一主键关联映射与单向一对一主键关联映射的区别就是,单向一对一关联映
射,在person端能看到idCard,而idCard不能看到Person端。而双向一对一关联映射就是在idCard端也能看到
person,也就是不但在Person.hbm.xml中加上
签。
如下图所示:
我们来实现:
Person实体类:同单向一对一主键关联映射的Person实体类一样
Person对象关系映射配置文件:同单向一对一主键关联映射的Person对象关系映射配置文件一样
IdCard实体类:
package com.demo.domain;
public class IdCard {
private int id;
private String cardNo;
//在一方加入另一方的引用
private Person person;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getCardNo() {
return cardNo;
}
public void setCardNo(String cardNo) {
this.cardNo = cardNo;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
}
@Override
public String toString() {
return "IdCard [id=" + id + ", cardNo=" + cardNo + ", person=" + person + "]";
}
}
IdCard对象关系映射配置文件:
测试类代码:
package com.demo.test;
import org.hibernate.Session;
import com.demo.domain.HibernateUtils;
import com.demo.domain.IdCard;
import com.demo.domain.Person;
import junit.framework.TestCase;
/**
* 双向一对一关联映射(Person<--->IdCard)
* @author Administrator
* @date 2016年12月8日
*/
public class One2OneTest extends TestCase {
public void testSave1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = new IdCard();
idCard.setCardNo("1111111");
Person person = new Person();
person.setName("张三");
//建立一对一关联映射
person.setIdCard(idCard);
//没有抛出TransientObjectException
//是由一对一关联映射的特性决定的,它必须先保存关联对象IdCard
//这样它采用foreign映射策略才能取得关联对象的标识
//也就是它默认了cascade属性
//保存Person对象
session.save(person);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
public void testSave2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Person person = new Person();
person.setName("李四");
IdCard idCard = new IdCard();
idCard.setCardNo("2222222");
//建立一对一关联映射
idCard.setPerson(person);
//保存IdCard对象
session.save(idCard);//人是不会保存进入数据库的,想要保存需要加:person.setIdCard(idCard);
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
public void testLoad1() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
Person person = (Person)session.load(Person.class, 1);
System.out.println("person.name=" + person.getName());
System.out.println("person.cardNo=" + person.getIdCard().getCardNo());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
public void testLoad2() {
Session session = null;
try {
session = HibernateUtils.getSession();
session.beginTransaction();
IdCard idCard = (IdCard)session.load(IdCard.class, 1);
System.out.println("idCard.cardNo=" + idCard.getCardNo());
System.out.println("idCard.person.name=" + idCard.getPerson().getName());
session.getTransaction().commit();
}catch(Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
}finally {
HibernateUtils.closeSession(session);
}
}
}
testSave1()方法
控制台输出:
数据库显示:
testSave2()方法
控制台输出:
数据库显示:
testLoad1()方法
控制台输出:
testLoad2()方法
控制台输出:
对于双向一对一主键关联映射一直没想明白,在IdCard对象关系映射文件中的
性为all,保存idCard对象时候,还是保存不了person对象,不知道原因是什么?待解决