【HIbernate框架学习】:Hibernate对象关系映射之一对一关联映射(一)

本文详细介绍了在软件开发中一对一关联映射的概念及其两种实现策略:主键关联和唯一外键关联。通过具体实例展示了单向及双向一对一主键关联映射的实现方式,包括实体类的设计与Hibernate配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

        一对一关联映射在实际生活中是比较常见的,如人与身份证的关系,通过人这个对象可以找到身份证相关的信

,也可以通过身份证这个对象找到人相关的信息。

       有两种策略可以实现一对一的关联映射:

       主键关联:即让两个对象具有相同的主键值,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来

维护它们之间的关系,仅通过表的主键来关联;

       唯一外键关联:外键关联,本来是用于多对一的配置,但是如果加上唯一的限制之后,也可以用来表示一对一关

联关系。

       

      单向一对一主键关联映射

      我们先来假设一个场景,从Person中能看到IdCard,也就是把idCard数据表中的主键拿过来当做person表的主

键,单向一对一主键关联映射的实现就是它们的主键相等。一对一关联映射是通过在一方(Person)的对象关系配置

文件加入<one-to-one>元素定义的。这里的方向是由Person--->IdCard。

      如下图所示:

      

      下面我们来实现:

       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对象关系映射配置文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.demo.domain.Person" table="person">
		<id name="id">
			<!-- 采用foreign生成策略,forgeign会取得关联对象的标识 -->
			<generator class="foreign">
				<!-- property只关联对象 -->
				<param name="property">idCard</param>
			</generator>
		</id>
		<property name="name"/>
		
		<!-- 
			one-to-one指示hibernate如何加载其关联对象,默认根据主键加载
			也就是拿到关系字段值,根据对端的主键来加载关联对象
		
			constrained="true表示,当前主键(person的主键)还是一个外键
			参照了对端的主键(IdCard的主键),也就是会生成外键约束语句
		 -->
		<one-to-one name="idCard" constrained="true"/>
		
	</class>
</hibernate-mapping>

       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对象关系映射配置文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.demo.domain.IdCard" table="idCard">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="cardNo"/>
	</class>
</hibernate-mapping>

       测试类代码:

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中加上<one-to-one>标签,同时在IdCard.hbm.xml文件中加上<one-to-one>标

签。

       如下图所示:

       

       我们来实现:

       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对象关系映射配置文件:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC 
	"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
	"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
	<class name="com.demo.domain.IdCard" table="idCard">
		<id name="id">
			<generator class="native"/>
		</id>
		<property name="cardNo"/>
		
		<!-- 一对一关联映射 --> 
                <one-to-one name="person" /> 
		
	</class>
</hibernate-mapping>

       测试类代码:

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对象关系映射文件中的<one-to-one>元素中设置了级联属

性为all,保存idCard对象时候,还是保存不了person对象,不知道原因是什么?待解决



      
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值