hibernate入门(七):一对一

3.一对一关系映射:

典型的实例:一个人有一个身份证,而一个身份证只属于某一个人。以此为模型实现一对一关系的映射。下面的实例先以主键进行关联:

主键关联从表的主键同时又作为外键参考主表的主键。比如在下面的实例中,人作为主表,身份证作为从表。

>>步骤一,建立Person类及相关的实体配置文件。

package com.asm.hibernate.domain;
public class Person {
	private int id;
	private String name;
	private IdCard idCard;
...省略相应的get/set方法。
}	

 

配置文件:person.hbm.xml 和前面的配置一样,只需要留意下</one-to-one>元素,内容如下:

<hibernate-mapping package="com.asm.hibernate.domain">
	<class name="Person">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name"></property>
		<one-to-one name="idCard"></one-to-one>
	</class>
</hibernate-mapping>

 

>>步骤二,建立IdCard类及相关的实体配置文件。

package com.asm.hibernate.domain;
import java.util.Date;
public class IdCard {
	private int id;
	private Date validity;
	private Person person;	
	...省略相应的get/set方法。
}

 

从表配置文件:IdCard.hbm.xml ,内容如下:

<hibernate-mapping package="com.asm.hibernate.domain">
	<class name="IdCard">
		<id name="id">
			<generator class="foreign">
				<param name="property">person</param>
			</generator>
		</id>
		<property name="validity"></property>
		<one-to-one name="person" constrained="true"></one-to-one>
	</class>
</hibernate-mapping>

 

配置文件说明:由于上面提到的是采取主键关联,即是说这里的id即是主键,同时也是(关联相关表的)外键,因此,以下对id的生成采取了”foreign”方式,其实这种方式也就指明了主键同时为外键。下面的<param>指定了外键的参考信息,此元素中的内容指明了它参考<one-to-one>person。 注意在<one-to-one name="person" constrained="true">中设定了constrained属性,其作用是说明该配置文件所映射表的主键同时作为外键,参照关联类对应表的主键。设定了此属性可用“show create table idcard”查看表idcard的定义发生了变化。

>>步骤三,修改主配置文件,关联上面的实体配置文件。

>>步骤四,编写测试类,OneToOneTest.java 内容如下:省略导入的包。

package com.asm.hibernate.test;
public class OneToOneTest {
	public static void main(String[] args) {
		add();
	}
	static void add() {
		Session s = null;
		Transaction tr = null;
		try {
			s = HibernateUtil.getSession();
			tr = s.beginTransaction();

			Person person = new Person();
			person.setName("pName");
			IdCard idCard = new IdCard();
			idCard.setValidity(new Date());
			
			//分别注释掉以下两句,看程序执行情况
			person.setIdCard(idCard);
			idCard.setPerson(person);

			s.save(person);
			s.save(idCard);
			tr.commit();
		} finally {
			if (s != null)
				s.close();
		}
	}
}

 

说明:留意上面的注释,如果注释掉第一句,发现一切正常,因为主对象是可以没有此属性,它的实体配置文件也基本与前面一样。而如果注释掉下面一句,将会报错,原因是“attempted to assign id from null one-to-one property: person”,IdCard的实体配置文件关联了一个表,而它采取主键关联,而主键关联要依赖于person属性的id,如果这里注释掉,即没有了此属性,它也关联不了相应的id。简单的说,IdCard来要关联Person,我们称它为从对象,而person并不关联谁,我们称为主对象。现在只要记住,从对象关联了表(关联了主对象),必须设定它所关联的主对象属性

>>步骤五,编写两个查询方法,一个查询主对象,主要代码:

static Person query(int id) {
		Session s = null;
		Transaction tr = null;
		try {
			s = HibernateUtil.getSession();
			tr = s.beginTransaction();
			Person p = (Person) s.get(Person.class, id);
			System.out.println("身份证有效期:" + p.getIdCard().getValidity());
			tr.commit();
			return p;
		} finally {
			if (s != null)
				s.close();
		}
	}  

 

然后再在main方法中调用此方法,并开启控制台数据库库语言显示后,可以从控制台看出查询主对象只select一次;再增加一个查询从对象的方法,主要代码:

static IdCard query2(int id) {
		Session s = null;
		Transaction tr = null;
		try {
			s = HibernateUtil.getSession();
			tr = s.beginTransaction();
			IdCard idCard = (IdCard) s.get(IdCard.class, id);
			//System.out.println("人的名字:" + idCard.getPerson().getName());
			//去掉上一句注释后,发现会查询两次。
			tr.commit();
			return idCard;
		} finally {
			if (s != null)
				s.close();
		}
	}

 

同样在main方法中调用此方法,并开启控制台数据库库语言显示后。从控制台看出也只会查询一次,但是如果去掉注释后发现会查询两次。  接着,在此例的基础上修改成外键关联。

外键关联从表的主键并不作为外键参考主表的主键,而是将其它字段作为外键参的主键。

其实在上例的基础上,我们只需要修改IdCard.hbm.xml配置文件即可,修改后的内容如下:

<hibernate-mapping package="com.asm.hibernate.domain">
	<class name="IdCard">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="validity"></property>
		<many-to-one name="person" column="person_id" unique="true" />
	</class>
</hibernate-mapping> 

 

说明:由于采取了外键关联,所以这里的从表的主键将不再作为外键参考主表的主键,所以它会采取一般的方式生成主键,即<id>生成和以前的那此相同采取“native”方式。 另注意到< many-to-one >,发现增加了unique有属性,这样尽管是多对一,但能有效保证实质是一对一。  这时运行原OneToOneTest,发现仍是和以前一样。 如果我们再修改Person的实体配置文件<one-to-one>如下:

<one-to-one name="idCard" property-ref="person"/> 特别要注意到property-ref 属性。可以结合执行后表的结构来看。其实如果注释掉此句,其结果就是通过身份证可以查看到Person的相关信息,但是通过Person却不能找到身份证信息,因为Hibernate完全依赖实体配置文件(映射文件)。注释掉当然就不能找到。而事实上这时在OneToOne中调用query方法,会发现出现空指针异常。其实在前面的关联关系中,最终都是实现了双向关联,而这里如果注释掉此句,正好成了单向关联的一个例证。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值