Hibernate关系映射学习点滴2:一对多和多对多关系映射

一对多关系映射

基本使用方法:

DeptModel: (1方)

package cn.javass.h4.dept;

import java.util.HashSet;
import java.util.Set;

public class DeptModel {
	private int id;
	private String name;

	//方法1: 对集合初始化
	private Set<SubDeptModel> subDepts = new HashSet<SubDeptModel>();
	//方法2: 不对集合初始化;方法1和2的区别见下面的说明
	//private Set<SubDeptModel> subDepts;
	
	public int getId() {
		return id;
	}
	public void setId(int uuid) {
		this.id = uuid;
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}

	public Set<SubDeptModel> getSubDepts() {
		return subDepts;
	}
	public void setSubDepts(Set<SubDeptModel> subDepts) {
		this.subDepts = subDepts;
	}


}



SubDeptModel: (多方)

package cn.javass.h4.dept;

public class SubDeptModel {
	private int id;
	private String name;
	private DeptModel dept;

	
	public int getId() {
		return id;
	}
	public void setId(int uuid) {
		this.id = uuid;
	}

	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public DeptModel getDept() {
		return dept;
	}
	public void setDept(DeptModel dept) {
		this.dept = dept;
	}

	
	
}

.hbm配置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
'-//Hibernate/Hibernate Mapping DTD 3.0//EN'
'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
<hibernate-mapping>
	<class name="cn.javass.h4.dept.DeptModel" table="tbl_dept">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name"></property>
		<set name="subDepts" inverse="true"  cascade="save-update,delete">
			<key column="deptId"/> <!--这里depId是SubDept表的外键字段,默认和本表的id字段关联 -->
			<one-to-many class="cn.javass.h4.dept.SubDeptModel"></one-to-many>
		</set>
	</class>

	<class name="cn.javass.h4.dept.SubDeptModel" table="tbl_subdept"> 
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name"></property>
		<many-to-one name="dept" column="deptId" class="cn.javass.h4.dept.DeptModel"
				  cascade="save-update,delete"
				 >
		</many-to-one>
	</class>
	
</hibernate-mapping>

说明:

1. 对于one-to-many映射 默认情况下, lazy属性为true。

    对于many-to-one, 默认情况下, lazy属性为proxy;

    对于one-to-one, 因为有contrained 属性的影响, Hibernate总是采取预先抓取, 而不管lazy属性为何值, 如果 contrained="true", Hibernate采取 select的抓取策略;如果contrained="false", Hibernate采用left-outer-join的抓取方式。

2. 集合字段配置为List 和Set的区别,因为List是有序的集合, 可以重复; Set是无序,无重复的,所以配置上有一定区别

 配置为Set的形式最简单,如下:

    

		<set name="subDepts" inverse="true"  cascade="save-update,delete">
			<key column="deptId"/> 
			<one-to-many class="cn.javass.h4.dept.SubDeptModel"></one-to-many>
		</set>

 配置为List需要有一个<index>或者<list-index>子元素,用以区分元素的顺序:

		<list name="subDepts" inverse="true"  cascade="save-update,delete">
			<key column="deptId"/> 
			<list column="id"> </list>
			<one-to-many class="cn.javass.h4.dept.SubDeptModel"></one-to-many>
		</list>


3.  private Set<SubDeptModel> subDepts = new HashSet<SubDeptModel>();

     private Set<SubDeptModel> subDepts; 

     的区别:

     在“一“方定义Set或者List的时候, 可以对Set/List进行初始化,也可以不进行初始化。以Set为例子:

     如果Set进行了初始化,那么Hibernate在加载Set数据时, 以你初始化的Set类型加载数据,比如你初始化类型是HashSet, 那么加载的subDepts就是HashSet集合。

     如果不对Set进行初始化, 那么Hibernate默认以PersistentSet类型加载数据。

     另外, 在程序中添加数据的时候, 如果通过new 对Set进行了初始化, 那么程序中只要通过 dept.getSubDepts.add(subDept)的形式添加集合项;而如果没有对Set进行初始化, 那么就需要手动创建一个Set, 代码类似如下:

Set subDepts = new HashSet(); 

subDepts.add(subdept) ;

dept.setSubDepts(subDepts);  


4. <Set>元素和<Key>元素

Set元素某些方面类似于 <one-to-one>, 他只是定义了一个关系, 而不是定义一个新的数据表列。 默认情况下, 关联关系在一方的所对应的字段就是Id主键字段, 通过

<key column="deptId"/> 的形式, 使的一方的主键列和多方的deptId 表列相互关联。

         如果关联关系在一方对应的字段是非主键字段, 那么就需要使用到<key>元素的 property-ref属性,具体例子可以看下面:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
'-//Hibernate/Hibernate Mapping DTD 3.0//EN'
'http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd'>
<hibernate-mapping>
	<class name="cn.javass.h4.dept.DeptModel" table="tbl_dept">
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name"></property>
		<property name="subDeptKey" type="int" unique="true"></property>
		<set name="subDepts" inverse="true"  cascade="save-update,delete">
			<key column="deptId" property-ref="subDeptKey"/>
			<one-to-many class="cn.javass.h4.dept.SubDeptModel"></one-to-many>
		</set>
	</class>

	<class name="cn.javass.h4.dept.SubDeptModel" table="tbl_subdept"> 
		<id name="id">
			<generator class="native" />
		</id>
		<property name="name"></property>
		<many-to-one name="dept" column="deptId" class="cn.javass.h4.dept.DeptModel" property-ref="subDeptKey"
				  cascade="save-update,delete"
				 >
		</many-to-one>
	</class>
	
</hibernate-mapping>

上面的例子中,一方 首先定义了一个非主键列 subDeptKey, 然后 key元素设置成 <key column="deptId" property-ref="subDeptKey"/>, 使得 dept表的subDeptKey和 subDept表的 depId相关联;同样的,在同一个关联中, 一方的一对多关系和多方的多对一关系应该是一致的, 所以需要在多方的many-to-one关系中也设置property-ref属性, 因为默认情况下, many-to-one关联的是一方的主键列。

        这个例子中也进一步说明, <Set>元素只是说明一种关系,并没有定义出一个新的表列,所以如果需要通过property-ref关联非主键列的话, 需要预先通过

<property name="subDeptKey" type="int"></property>的形式预先定义好表列。

        还有一点要引起注意:无论是在one-to-one还是many-to-one映射中, column一般指的时本表的字段,property-ref属性引用的都是关联关系中另一方的表/实体的字段。而在one-to-many的映射关系中,<key>元素中的column和property-ref表达的含义正好相反,column指向的是关联关系中另一方的表/实体的字段, 而property-ref指向的是本表/实体的字段。



多对多关联关系

  多对多关系也很常见,例如学生与选修课之间的关系,一个学生可以选择多门选修课,而每个选修课又可以被多名学生选择。数据库中的多对多关联关系一般需采用中间表的方式处理,将多对多转化为两个一对多。

数据表间多对多关系如下图:

多对多关系在hbm文件中的配置信息:

学生:

<?xml version="1.0" encoding="utf-8"?>
<!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.suxiaolei.hibernate.pojos.Student" table="student">
<id name="id" type="integer">
<column name="id"></column>
<generator class="increment"></generator>
</id>

<property name="name" column="name" type="string"></property>

<set name="courses" inverse="false" cascade="save-update" table="student_course">
<key column="student_id"></key>
<many-to-many class="com.suxiaolei.hibernate.pojos.Course"
column
="course_id"></many-to-many>
</set>
</class>
</hibernate-mapping>

课程:

<?xml version="1.0" encoding="utf-8"?>
<!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.suxiaolei.hibernate.pojos.Course" table="course">
<id name="id" type="integer">
<column name="id"></column>
<generator class="increment"></generator>
</id>

<property name="name" column="name" type="string"></property>

<set name="students" inverse="true" cascade="save-update" table="student_course">
<key column="course_id"></key>
<many-to-many class="com.suxiaolei.hibernate.pojos.Student"
column
="student_id"></many-to-many>
</set>
</class>
</hibernate-mapping>

  其实多对多就是两个一对多,它的配置没什么新奇的相对于一对多。在多对多的关系设计中,一般都会使用一个中间表将他们拆分成两个一对多。<set>标签中的"table"属性就是用于指定中间表的。中间表一般包含两个表的主键值,该表用于存储两表之间的关系。由于被拆成了两个一对多,中间表是多方,它是使用外键关联的,<key>是用于指定外键的,用于从中间表取出相应的数据。中间表每一行数据只包含了两个关系表的主键,要获取与自己关联的对象集合,还需要取出由外键所获得的记录中的另一个主键值,由它到对应的表中取出数据,填充到集合中。<many-to-many>中的"column"属性是用于指定按那一列的值获取对应的数据。

  例如用course表来说,它与student表使用一个中间表student_course关联。如果要获取course记录对应的学生记录,首先需要使用外键"course_id"从student_course表中取得相应的数据,然后在取得的数据中使用"student_id"列的值,在student表中检索出相关的student数据。其实,为了便于理解,你可以在使用course表的使用就把中间表看成是student表,反之亦然。这样就可以使用一对多的思维来理解了,多方关联一方需要外键那么在本例子中就需要"course_id"来关。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值