一对多(客户表与联系人表为例):
一对多关系中习惯性的把一方称为主表,把多方称为从表,外键指的是从表中有一列,取值参照主表的主键,这一列就是外键。
举例:一方为客户,多方为联系人
在客户的实体类中需要配置一个set集合,包含多个联系人。
private Set<LinkMan>linkmans = new HashSet<LinkMan>();
在联系人的实体类中配置一个客户对象
private Customer customer;//用它的主键,对应联系人表中的外键
客户的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.shuai.domain">
<class name="Customer" table="cst_customer">
<id name="custId" column="cust_id">
<generator class="native"></generator>
</id>
<property name="custName" column="cust_name"></property>
<property name="custLevel" column="cust_level"></property>
<property name="custSource" column="cust_source"></property>
<property name="custIndustry" column="cust_industry"></property>
<property name="custAddress" column="cust_address"></property>
<property name="custPhone" column="cust_phone"></property>
<!-- 一对多关系映射
涉及的标签
set:用于映射set集合属性
属性:
name:指定集合属性的名称
table:在一对多的时候写不写都可以。
它指定的是集合元素所对应的表
one-to-many:用于指定当前映射配置文件所对应的实体和集合元素所对应的实体是一对多关系。
属性:
class:指定集合元素所对应的实体类名称。
key:用于映射外键字段的。
属性:
column:指定从表中的外键字段名称
-->
<set name="linkmans" table="cst_linkman">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
</class>
</hibernate-mapping>
联系人的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.shuai.domain">
<class name="LinkMan" table="cst_linkman">
<id name="lkmId" column="lkm_id">
<generator class="native"></generator>
</id>
<property name="lkmName" column="lkm_name"></property>
<property name="lkmGender" column="lkm_gender"></property>
<property name="lkmPhone" column="lkm_phone"></property>
<property name="lkmMobile" column="lkm_mobile"></property>
<property name="lkmEmail" column="lkm_email"></property>
<property name="lkmPosition" column="lkm_position"></property>
<property name="lkmMemo" column="lkm_memo"></property>
<!-- 多对一关系映射
涉及的标签:
many-to-one:用于建立多对一的关系映射配置
属性:
name:指定的实体类中属性的名称
class:该属性所对应的实体类名称。如果在hibernate-mapping上没有导包,则需要写全限定类名
column:指定从表中的外键字段名称
-->
<many-to-one name="customer" class="Customer" column="lkm_cust_id" /> </class>
</hibernate-mapping>
多对多(用户表与角色表为例):
一个用户可以具备多个角色,一个角色也可以赋予多个用户,用户和角色之间的关系是多对多,多对多的实现方式靠的是第三张表,也叫中间表,里面包含了两个字段,分别引用各自的主键,同时这两个字段还是联合主键,其中用户表和中间表的关系是一对多,角色表和中间表的关系也是一对多。
一个用户可以具有多个角色,所以在用户实体类中应该包含多个角色的信息。
用户的实体类中定义一个set集合用于存放多个联系人:
private Set<SysRole>roles = new HashSet<SysRole>(0);
一个角色可以赋予多个用户,所以在角色的实体类中应该包含多个用户的信息。
角色的实体类中定义一个set集合用于存放多个用户:
private Set<SysUser>users = new HashSet<SysUser>(0);
用户的配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.shuai.domain">
<class name="SysUser" table="sys_user">
<id name="userId" column="user_id">
<generator class="native"></generator>
</id>
<property name="userCode" column="user_code"></property>
<property name="userName" column="user_name"></property>
<property name="userPassword" column="user_password"></property>
<property name="userState" column="user_state"></property>
<!-- 多对多关系映射
涉及的标签:
set:用于映射集合属性
属性:
name:指定集合属性的名称
table:指定的是中间表的名称,在多对多的配置时,必须写。
key:指定外键字段
属性:
column:指定的是当前映射文件所对应的实体在中间表的外键字段名称
many-to-many:指定当前映射文件所对应的实体和集合元素所对应的实体是多对多的关系
属性:
class:指定集合元素所对应的实体类
column:指定的是集合元素所对应的实体在中间表的外键字段名称
-->
<set name="roles" table="user_role_rel">
<key column="user_id"></key>
<many-to-many class="SysRole" column="role_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://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.shuai.domain">
<class name="SysRole" table="sys_role">
<id name="roleId" column="role_id">
<generator class="native"></generator>
</id>
<property name="roleName" column="role_name"></property>
<property name="roleMemo" column="role_memo"></property>
<!-- 多对多关系映射 -->
<set name="users" table="user_role_rel">
<key column="role_id"></key>
<many-to-many class="SysUser" column="user_id"></many-to-many>
</set>
</class>
</hibernate-mapping>
保存时遇到的问题:
因为双向维护了关系,而且持久态对象可以自动更新数据库,更新客户的时候会修改一次外键,更新联系人的时候同样也会修改一次外键,这样就会产生多余的sql,解决的方法很简单,只需要将一方放弃外键的维护权即可,也就是关系不是双方维护的,只需要交给某一方维护就可以了,通常我们都是交给多的一方去维护的。举个例子,一个老师对应多个学生,一个学生对应一个老师,这是典型的一对多。那么一个老师如果要记住所有学生的名字很难的,但如果让每个学生记住老师的名字应该不难。其实就是这个道理。
所以在一对多中,一的一方都会放弃外键的维护权(关系的维护)。这个时候如果想让一的一方放弃外键的维护权,只需要进行如下的配置即可。
解决多一条update语句的问题:
<set name="linkmans" table="cst_linkman" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
inverse的默认值是false,代表不放弃外键维护权,配置值为true,代表放弃外键的维护权。
修改中遇到的问题:
什么是级联操作:
级联操作是指当主控方执行保存、更新或者删除操作时,其关联对象(被控方)也执行相同的操作。在映射文件中通过对cascade属性的设置来控制是否对关联对象采用级联操作,级联操作对各种关联关系都是有效的。
级联操作的方向性:
级联是有方向性的,所谓的方向性指的是,在保存一的一方级联多的一方和在保存多的一方级联一的一方。
【保存客户级联联系人】
首先要确定我们要保存的主控方是那一方,我们要保存客户,所以客户是主控方,那么需要在客户的映射文件中进行如下的配置。
代码如下:
解决报错的问题,配置级联保存更新:
<set name="linkmans" table="cst_linkman" cascade="save-update" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
删除操作:
删除从表数据,可以随意的删除
删除主表的数据:
(1)默认情况下会把外键字段先置为null,然后删除从表数据,如果在数据库的表结构上,外键字段有非空约束,默认情况就会报错了。
(2)如果配置了放弃维护关联关系的权利,则不能删除,因为在删除的时候它根本不会去更新从表的外键字段。
(3)如果还想删除,使用级联删除。在实际开发中,级联删除请慎用。
级联删除的配置:
<set name="linkmans" table="cst_linkman" cascade="delete" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>
如果想有之前的级联保存或更新,同时还想有级联删除,如下:
级联删除的配置:
<set name="linkmans" table="cst_linkman" cascade="delete,save-update" inverse="true">
<key column="lkm_cust_id"></key>
<one-to-many class="LinkMan"/>
</set>