上次我们说到了hibernate映射关系中的一对一关系,可是,我们知道,在实际应用中,我们最常遇到的还是一对多的关系。所以,今天我们来看看一对多关系的映射是怎么做到的。
一、实体
//人
public class Person1nfk implements Serializable {
private int personid;
private String name;
private int age;
private Set addresses=new HashSet();
//地址
public class Address1nfk implements Serializable {
private int addressid;
private String addressdetail;
二、外键–关联映射法
1、单向
- 一对多
一个人(Person)对应多个地址(Address),比如家庭地址、公司地址。
<hibernate-mapping>
<class name="com.lavasoft.dx._1_n_fk.Person1nfk" table="PERSON_1nfk">
<id name="personid">
<generator class="identity"/>
</id>
<property name="name"/>
<property name="age"/>
<!--映射集合属性,关联到持久化类,inverse="false"表示主控端在Person1nfk端,lazy="false"表示不采用延迟加载-->
<set name="addresses"
table="ADDRESS_1nfk"
cascade="all"
>
<!--确定关联的外键列-->
<key column="personid"/>
<!--用以映射到关联类属性-->
<one-to-many class="com.lavasoft.dx._1_n_fk.Address1nfk"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.lavasoft.dx._1_n_fk.Address1nfk" table="ADDRESS_1nfk">
<id name="addressid">
<generator class="identity"/>
</id>
<property name="addressdetail"/>
</class>
</hibernate-mapping>
解说1: inverse的真正作用就是指定由哪一方来维护之间的关联关系。当一方中指定了“inverse=false”(默认),那么那一方就有责任负责之间的关联关系。
解说2: Set集合属于无序集合,映射时只需指定Set集合的key(外键列)、element(元素列),以外键列、元素列(非空)作为联合主键;元素列为空时,Set集合表没有主键。
- 多对一
多个人(Person)对应一个地址(Address)。
<hibernate-mapping>
<class name="com.lavasoft.dx._n_1_fk.Personn1fk" table="PERSON_n1fk">
<id name="personid">
<generator class="identity"/>
</id>
<property name="name"/>
<property name="age"/>
<!--用来映射关联PO column是Address在该表中的外键列名,inverse="false"表示主控端在Person1nfk端-->
<many-to-one name="addressn1fk" column="addressId"/>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.lavasoft.dx._n_1_fk.Addressn1fk" table="ADDRESS_n1fk">
<id name="addressid">
<generator class="identity"/>
</id>
<property name="addressdetail"/>
</class>
</hibernate-mapping>
2、双向
- 一对多
一个人(Person)对应多个地址(Address)。
<hibernate-mapping>
<class name="com.lavasoft.sx._1_n_fk.Person1nfk_sx" table="PERSON_1nfk_sx">
<id name="personid">
<generator class="identity"/>
</id>
<property name="name"/>
<property name="age"/>
<!--映射集合属性,关联到持久化类-->
<set name="addresses" inverse="true" cascade="all">
<!--column用于指定外键列名-->
<key column="personid" not-null="true"/>
<!--映射关联类-->
<one-to-many class="com.lavasoft.sx._1_n_fk.Address1nfk_sx"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.lavasoft.sx._1_n_fk.Address1nfk_sx" table="ADDRESS_1nfk_sx">
<id name="addressid">
<generator class="identity"/>
</id>
<property name="addressdetail"/>
<!--映射关联属性,column属性指定外键列名-->
<many-to-one name="person1nfk"
class="com.lavasoft.sx._1_n_fk.Person1nfk_sx"
fetch="select"
cascade="save-update">
<column name="personid" not-null="true"/>
</many-to-one>
</class>
</hibernate-mapping>
解说1: inverse=true的含义: 由双向关联另一方维护该关联,己方不维护该关联(只能进行查询操作)。在上代码中,由Address1nfk_sx类这方维护该关系。
解说2:
Inverse:负责控制关系,默认为false,也就是关系的两端都能控制,但这样会造成一些问题,更新的时候会因为两端都控制关系,于是重复更新。一般来说有一端要设为true。
Cascade:负责控制关联对象的级联操作,包括更新、删除等,也就是说对一个对象进行更新、删除时,其它对象也受影响,比如我删除一个对象,那么跟它是多对一关系的对象也全部被删除。
解说3: fetch抓取策略:默认是fetch=”select”,另外发送一条select语句抓取当前对象关联实体或集合;当配置fetch=”join”,hibernate会通过select语句使用外连接来加载其关联实体或集合,此时lazy会失效
三、连接表–关联映射法
1、单向
- 一对多
一个人(Person)对应多个地址(Address),比如家庭地址、公司地址。
<hibernate-mapping>
<class name="com.lavasoft.dx._1_n_tab.Person1ntab" table="PERSON_1ntab">
<id name="personid">
<generator class="identity"/>
</id>
<property name="name"/>
<property name="age"/>
<!--映射集合属性,join_1ntab是连接表表名-->
<set name="addresses"
table="join_1ntab"
>
<!--“column="personid"”确定PERSON_1ntab表关联到连接表的外键列名-->
<key column="personid"/>
<!--“column="addressid"”关联PERSON_1ntab表的Address1ntab对象的id在连接表中的列名-->
<!--“unique="true"表示1-N,Person1ntab是1,Address1ntab是多”-->
<many-to-many
column="addressid"
unique="true"
class="com.lavasoft.dx._1_n_tab.Address1ntab"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.lavasoft.dx._1_n_tab.Address1ntab" table="ADDRESS_1ntab">
<id name="addressid">
<generator class="identity"/>
</id>
<property name="addressdetail"/>
</class>
</hibernate-mapping>
- 多对一
多个人(Person)对应一个地址(Address)。
<hibernate-mapping>
<class name="com.lavasoft.dx._n_1_tab.Personn1tab" table="PERSON_n1tab">
<id name="personid">
<generator class="identity"/>
</id>
<property name="name"/>
<property name="age"/>
<!--使用join元素显式确定链接表-->
<join table="join_n1tab">
<!--映射关联所用的外键-->
<key column="personid"/>
<many-to-one name="addressn1tab"/>
</join>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.lavasoft.dx._n_1_tab.Addressn1tab" table="ADDRESS_n1tab">
<id name="addressid">
<generator class="identity"/>
</id>
<property name="addressdetail"/>
</class>
</hibernate-mapping>
2、双向
<hibernate-mapping>
<class name="com.lavasoft.sx._1_n_tab.Person1ntab_sx" table="PERSON_1ntab_sx">
<id name="personid">
<generator class="identity"/>
</id>
<property name="name"/>
<property name="age"/>
<!--映射集合属性,关联到持久化类-->
<!--table="join_1ntab_sx"指定了连接表的名字-->
<set name="addresses"
table="join_1ntab_sx"
cascade="all">
<!--column="personid"指定连接表中关联当前实体类的列名-->
<key column="personid" not-null="true"/>
<!--unique="true"表示当前实体类是"1",不是"n"-->
<many-to-many column="addressid"
unique="true"
class="com.lavasoft.sx._1_n_tab.Address1ntab_sx"/>
</set>
</class>
</hibernate-mapping>
<hibernate-mapping>
<class name="com.lavasoft.sx._1_n_tab.Address1ntab_sx"
table="ADDRESS_1ntab_sx">
<id name="addressid">
<generator class="identity"/>
</id>
<property name="addressdetail"/>
<!--映射关联属性,column属性指定外键列名-->
<join table="join_1ntab_sx"
inverse="true"
optional="true">
<key column="addressid"/>
<many-to-one name="person1ntab_sx"
column="personid"
cascade="all"
not-null="true"/>
</join>
</class>
</hibernate-mapping>
总结:
我们通过一对多映射关系的学习,了解了one-to-many和many-to-one的使用,那么下次我们将继续介绍many-to-many的映射关系。