hibernate的关联关系映射一共有7种:
1.单向多对一
2.单向一对多
3.单向一对一
4.单向多对多
5.双向多对一
6.双向一对一
7.双向多对多
一,单向多对一(many--to--one)
两个对象之间多对一的关系,比如员工(emp)和部门(dept),多个员工可以在一个部门,映射原理就是在多的一端添加一个外键指向一的一端的主键。
在多的一端的映射文件加入下面映射标签:
<many-to-one name="dept" column="DEPT_ID" class="com.vo.Dept"></many-to-one>
其中name属性值为Emp类中的dept属性,column为数据库生成的列名,是emp表的外键,class为Dept类所在包的路径。这样就可以在查询多的一端的信息时,就能自动把一的一端的信息同时查询出来。(此时一的信息是以懒加载的形式查询出来,当使用这个对象的时候才会向数据库发送select语句,如果在提交事务后在使用此对象,则会报懒加载异常,解决办法为查询出来后,进行初始化,如调用hibernate的initialize方法,Hibernate.initialize(object);)
二,单向一对多
单向一对多的映射和单向多对一的映射原理相同,都是在多的一端加入外键指向一的一端,
注意:它与多对一的区别是维护的关系不同
*多对一维护的关系是:多指向一的关系,有了此关系,加载多的时候可以将一加载上来
*一对多维护的关系是:一指向多的关系,有了此关系,在加载一的时候可以将多加载上来
在一的一端的映射文件加入下面映射标签:
<set name="emps" table="EMP">
<key column="DEPT_NO"></key>
<one-to-many class="com.vo.Emp"/>
</set>
三,单向一对一
一对一关联关系也是很常见的关联关系,如部门--部门经理,汽车--车位,人--身份证等等。
有两种策略可以实现一对一的关联映射:
唯一外键关联:外键关联,本来是用于多对一的配置,但是如果加上唯一的限制之后,也可以用来表示一对一关联关系。
在mrg类对应映射文件加入下列代码
<many-to-one name="dept" class="com.vo.Dept" column="DEPT_ID" unique="true"></many-to-one>
采用<many-to-one>标签来映射,指定多的一端unique为true,这样就限制了多的一端的多重性为一。
主键关联:即让两个对象具有相同的主键值,一个表中的外键列即主键列,以表明它们之间的一一对应的关系;数据库表不会有额外的字段来维护它们之间的关系,仅通过表的主键来关联
在mrg类对应映射文件加入下列代码
<hibernate-mapping>
<class name="com.vo.Mgr" table="MGR">
<id name="mid" column="MGR_ID">
<!-- 使用外键的方式生成主键 -->
<generator class="foreign">
<!-- property属性指定使用当前哪个持久化类的哪一个主键生成本表的主键,与one-to-one连用 -->
<param name="property">dept</param>
</generator>
</id>
<property name="mname" column="MGR_NAME"></property>
<!-- 采用foreign主键生成器的一端使用one to one节点映射关联属性, -->
<!-- constrained="true"在当前主键上加上外键约束 -->
<one-to-one name="dept" class="com.vo.Dept" constrained="true"></one-to-one>
</class>
</hibernate-mapping>
四,单向多对多
在多对多的映射关系中,两张表已经解决不了问题,所以需要一张中间表
在category类对应的映射文件加入以下代码:
<set name="products" table="PRODUCT_CATR">
<!-- 指定本类对应的中间表外键列 -->
<key column="CATEGORY_ID"></key>
<!-- 指定映射类型,及映射该类型所根据的中间表的外键,即product类对应在中间表的外键-->
<many-to-many class="com.vo.Product" column="PRODUCT_ID"/>
</set>
五,双向多对一
单向多对一,查询多能把一查出来,而查询一不能把多查出来,双向多对一就解决了这个问题
在单向多对一的基础上修改,在Dept封装类中加入一个set集合属性,并初始化private Set<Emp> emps=new HashSet<>();然后生成get set方法,之后修改Dept类对应的映射文件,加入下列代码:
<set name="emps" table="EMP">
<key column="DEPT_ID"></key>
<one-to-many class="com.vo.Emp"/>
</set>
其中set节点的name属性值为集合对应的属性名,table为set中的元素对应的记录放在哪一个数据表中,key中column指定多的表中的外键列的名字,one-to-many中class值是指定映射类型,(类的路径)<set>的三个属性:
cascade(级联)
1.none:当Session操纵当前对象时,忽略其他关联的对象。它是cascade属性的默认值
2.save-update:当通过Session的save()、update()及saveOrUpdate()方法来保存或更新当前对象时。
3.delete:当通过Session的delete()方法删除当前对象时,会级联删除所有关联的对象。
4.delete-orphan:删除孤儿。
5.all:包含save-update,delete的行为。
inverse(反转)
1.inverse 决定由双向关联哪一方来维护关联关系
2.inverse设置为false,则为主动方,主动负责维护关联关系,默认是false 。
3.inverse设置为true,则为被动方,由多的一端负责维护关联关系。
一般将一的一端设为true,以使多的一方维护关联关系,有效减少update语句
order-by
在查询时,对集合(set)中的元素进行排序,使用表的字段名,而不是属性名
六,双向一对一
对比单向一对一进行映射,需要在dept类中加入emp类对象作为成员属性,然后在dept映射文件中加入<one-to-one><one-to-one>标签
双向一对一唯一外键映射关键映射代码——在dept端新加入如下标签映射:
<one-to-one name="mgr" class="com.vo.Mgr" property-ref="dept"></one-to-one>
注意:一对一唯一外键关联双向采用<one-to-one>标签映射,必须指定<one-to-one>标签中的property-ref属性为关系字段的名称
双向一对一主键映射关键映射代码——在dept端新加入如下标签映射:
<one-to-one name="mgr" class="com.vo.Mgr" ></one-to-one>
七,双向多对多
双向的目的就是为了两端都能将对方加载上来,和单向多对多的区别就是双向需要在两端都加入标签映射,需要注意的是:
* 生成的中间表名称必须一样
* 生成的中间表中的字段必须一样
在单向基础上,在product类对应的映射文件加入以下代码:
<set name="categories" table="PRODUCT_CATR">
<key column="PRODUCT_ID"></key>
<many-to-many class="com.vo.Category" column="CATEGORY_ID"/>
</set>
单双向的区别即查询:
单向:通过这一端查询另一端,另一端查不了这一端。
双向:通过任意一端查另一端。