hibernate映射
集合映射
如果实体类有一个集合类型的属性,就需要一张额外的表,即所谓的集合表,这
个表有一个外键引用实体类对应的表的主键。
根据集合中存放的元素类型可以分为两种:1,值类型集合,元素是可识别的数据
库类型,如基本数据类型或字符串类型等;2,实体类型集合,元素是其他的实体。
** 对集合做映射时一般需要指定:
1)集合表的表名,在相应元素中使用属性table指定;
2)集合外键,是在子元素key中用属性column属性指定一个列名,他是一个外键
引用了实体表的主键;
3)集合元素,对于值类型集合,使用元素element指定;对于实体类型集合,使
用元素one-to-many或many-to-many。
4)如果是索引集合,如List,数组或Map(bag不是),还需要指定一个集合表中
的索引字段,用于对应到数组索引或List的索引,或者Map的key。
a) 如果是List或数组,需要指定(集合表中的)一个用于保存索引的列,用
元素list-index指定。
b) 如果是Map:key用map-key元素指定;如果key是一个实体引用,则是通过
map-key-many-to-many来配置。
JAVA的实体类中集合只能定义成接口不能定义成具体类,因为在运行时集合会被
替换成Hibernate的实现。
在实体类中声明集合时,可进行初始化。比如Set addresses = new HashSet();
这样做的目的是方便往集合中添加元素,调用getAddresses().add(element)就可
以了,不需再做是否为null的判断。 注意,我们只在把addresses初始化为一个
HashSet的实例,在运行时,集合会被Hibernate替换为自已的实现。
用于映射集合类的元素是由集合接口的类型决定的:
<set> 元素用来映射 java.util.Set 类型的属性;
<list> 元素用来映射 java.util.List 类型的属性;
<array>元素用来映射 对象类型的数组;
<primitive-array>元素用来映射 原始数据类型的数组;
<bag> 元素用来映射 java.util.List 类型的属性(允许重复但没有顺序);
<map> 元素用来映射 java.util.Map 类型的属性;
1,Set,一个用户(User)有多个地址,地址是字符串类型的。
<set name="addresses" table="itcast_useraddresses">
<key column="userId"></key>
<element type="string" column="address"></element>
</set>
2,List,与Set相比,需要在表中增加一列用于保存索引(元素在List中保存的
顺序,不对应实体的任何属性)。用<list-index>元素指定:
<list name="phoneNumbers" table="itcast_user_phonenumbers">
<key column="userId"></key>
<list-index column="idx"></list-index>
<element type="string" column="phoneNumber"></element>
</list>
3,a) 对象类型数组,跟配置list类似,只不过把list-index元素替换为index元
素,作用一样:
<array name="addresses2" table="itcast_user_addresses2">
<key column="userId"></key>
<index column="idx"></index>
<element type="string" column="address"></element>
</array>
b) 原始类型数组,把array元素名替换为array:
<primitive-array name="phoneNumbers2" table="user_phonenumbers2">
<key column="userId"></key>
<index column="idx"></index>
<element type="integer" column="phoneNumber"></element>
</primitive-array>
4,bag,可以有重复元素,但不保存顺序。实体中声明为java.util.List类型
(不用指定list-index,因为bag不保存顺序):
<bag name="addresses3" table="itcast_user_addresses3">
<key column="userId"></key>
<element type="string" column="address"></element>
</bag>
5,Map,需要映射key的value:
<map name="phoneNumbers3" table="itcast_user_phonenumbers3">
<key column="userId"></key>
<map-key type="string" column="idx"></map-key>
<element type="string" column="phoneNumber"></element>
</map>
* 有序集合
有两种方式实现:
a) 使用sort属性实现在内存中排序;
b) 使用order-by属性实现 在使用sql进行查询时使用order by指定顺序。
有序集合对于List或数组无效,因为列表元素的顺序由列表索引指明。
如果使用的是Set或Map类型的集合,并且在实体中对这个集合属性进行了初始化,
应是SortedSet或SortedMap实现类的实例(TreeSet或TreeMap)。
** sort属性
可以用于set或map映射,默认为unsorted,即不排序;可以设为natural,要求实
体要实现java.lang.Comparable接口。分类集合的行为象TreeSet或者TreeMap,
这是从数据库中取出记录后再在内存中进行排序。(在查询时有效)
** order-by属性
在set、bag或map映射中使用order-by属性,指定查询时生成的sql的order by子
句,这是在执行sql查询时指定排序(推荐)。如果使用了order-by,则返回的就
是可以保存顺序的集合实现类。
* 一对多与多对一映射:User与Group
在User.hbm.xml中增加:
<many-to-one name="group" column="groupId"></many-to-one>
在Group.hbm.xml中增加:
<set name="users">
<key column="groupId"></key>
<one-to-many column="parentId"/>
<set name="children">
<key column="parentId"/>
<!-- 集合中的元素还是Group -->
<one-to-many constrained="true"></one-to-one>
属性constrained="true"表示该类对应的表的的主键同时作为外键引用User
表的主键,默认为false。
在User.hbm.xml中增加:
<one-to-one name="idCard"></one-to-one>
** 基于外键的一对一
在IdCard.hbm.xml中增加:
<many-to-one name="user" column="userId" unique="true"/>
其中属性unique="true"说明这一列的值是唯一的,不能重复。基于外键的一
对一其实就是多对一的一个特例。
在User.hbm.xml中增加:
<one-to-one name="idCard" property-ref="user"></one-to-one>
!!其中property-ref属性用来指定关联类的一个属性,这个属性将会和外
键相对应,如果没有指定,会使用对方关联类的主键(所以上面的基于主键
的一对一时不用指定)。
* 多对多映射:Group与Role
在Group.hbm.xml中增加:
<set name="roles" table="itcast_groups_roles">
<key column="groupId"></key>
<many-to-many column="roleId"></many-to-many>
</set>
在Role.hbm.xml中增加:
<set name="groups" table="itcast_groups_roles">
<key column="roleId"></key>
<many-to-many column="groupId"></many-to-many>
</set>
双方一定要在set元素中指定相同的表名(这是指定的中间表的名字)。元素
many-to-many 的class 属性用于指定关联类(集合中的实体元素)的名称;因为
是多对多,关联类在中间表中也是用一个外键指定的,many-to-many中的column
属性用于指定这个外键的列名。
这是做的双向关联,此时双方都可以维护关系。去掉任何一方的映射,就是单向
的双对多关联。
* 属性:lazy
延迟加载,默认值为true,即集合的属性值默认是不加载的。强制加载可以通过
在session环境中使用这个集合属性或者使用:Hibernate.initialize(proxy);
当相关联的session关闭后,再访问懒加载的对象将出现异常。