hibernate3.2 (7)一对一关联映射

hibernate3.2 (七)一对一关联映射

一个人只能有一个身份证号码。

1对1单向关联,即单向引用,例如:person持有cardid的引用。

1对1双向关联,即双向引用,互相持有对对方的引用。

1对1主键关联,主键关联主键,也就是说有一方主键不需要自己建立,而是引用了另一方的主键。

1对1外键关联。

 

一、单向一对一主键关联映射:

通常使用一个特定的id生成器:

<?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.wyx.hibernate.IdCard">
		<id name="id">
			<generator class="native"/>
		</id>
	</class>
</hibernate-mapping>

 

<?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.wyx.hibernate.Person">
		<id name="id">
			<generator  class="foreign">
				<param name="property">idcCard</param>
			</generator>
		</id>
		<property name="name"/>
		<one-to-one name="idcCard" constrained="true"/>
	</class>
</hibernate-mapping>

这里的主键生成策略:

<id name="id">
<generator  class="foreign">
<param name="property">idCard</param>
</generator>
</id>

foreien表示person的主键来源于关联对象的标识,<param name="property">idCard</param>是固定写法,

表示该主键受约束,约束方来自<param name="property">指定的值,这里的值是person的关系字段(关联对象),体现在实体类或者实体类的映射关系上也就是表明该主键受的约束是来自其他表。这样配置后,person就能拿到idCard的主键作为自己的主键了。

 

关系型数据库两张表如果存在关联,必须存通过外键表达。体现在对应的实体类中就是通过关系字段。体现在实体类的映射文件上就是只要存在外键关系,就必须存在<many-to-one><one-to-one>等的标签映射这种外键关系。

这里的一对一主键关联比较特殊,在关系型数据库两张表中看不出有外键关联,person的主键既是主键又充当了外键,因为该主键参考了idCard的主键。

 

那么我们加载person的时候,根据one-to-one标签,这个标签标示怎么加载这个引用对象,过程是把person中的主键譬如1拿出来,到idCard的id中去比对,找到引用对象。最后我们别忘了把外键约束constrained="true加上,表示person的主键上存在一个约束,person的主键作为外键参照了idCard。

 

最后,写一个测试类:

	public void one2oneSaveTest(){
		Session session = HibernateUtils.getSession();
		try {
			session.beginTransaction();
			IdCard idcCard = new IdCard();
			//idcCard.setId(12345678);
			Person person = new Person();
			person.setIdcCard(idcCard);
			person.setName("小明");
			session.save(person);
			session.getTransaction().commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally{
			HibernateUtils.closeSession(session);
		}
	}

 打印:

Hibernate: insert into IdCard values ( )
Hibernate: insert into Person (name, id) values (?, ?)

 

为什么idcCard 没有save,也没有设置casecade属性,就能级联添加了呢?

因为一对一主键关联映射比较特殊,内置默认了casecade属性,系统会自动先把idCard保存。

一对一主键关联映射,体现在数据库上时没有多余的字段去维护关联关系,仅仅通过主键去互相关联,

 

二、单向一对一唯一外键关联映射

 

一对一外键关联会生成一个字段维护外键关系,是多对一外键关联映的一种特例,与多对一不同的只是不允许多个person指向一个card,即不允许card属性出现重复值,通过限定多的一方的unique = true,这样就限制了多的一方对象关联唯一。

<many-to-one name=""idCard"" unique="true"/>

 

 与多对一需要注意的问题一样,在save person对象之前,必须先save idCard对象,或者设置casecade = true。

<?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.wyx.hibernate.Person">
		<id name="id">
			<generator  class="native"/>
		</id>
		<property name="name"/>
		<many-to-one name="idCard" unique="true" cascade="all"/>
	</class>
</hibernate-mapping>

 

public void testone2one_Save(){
		Session session = HibernateUtils.getSession();
		try {
			session.beginTransaction();
			IdCard idcCard = new IdCard();
			idcCard.setCardid("370211198606150012");
			Person person = new Person();
			person.setIdcCard(idcCard);
			person.setName("小明");
			session.save(person);
			session.getTransaction().commit();
		} catch (HibernateException e) {
			e.printStackTrace();
			session.getTransaction().rollback();
		}finally{
			HibernateUtils.closeSession(session);
		}
	}

 打印输出:

Hibernate: insert into IdCard (cardid) values (?)
Hibernate: insert into Person (name, idCard) values (?, ?)

 

双向一对一唯一外键关联映射、双向一对一主键关联映射用的不是很多,以后遇到再加以说明。