今天讲了一些关于hibenate的映射关系,有一对多,多对一,一对一,多对多
等等,学完这节课,我还真想自己整理笔记的,整理到一半突然发现,汤老师的笔记整理的是那么的完美。
我希望看到我博客的人,能够吸收到更多充实的知识。虽然本人博客写了2个月了,毕竟还是菜鸟一个,不过呢,
在传智的2个月内已经学到了许多以前不曾知道的知识。下面我先是将汤老师的笔记复制了过来。以下还有代码,
我就说说作为我一个初学者,在学习中犯下的错误吧。我相信看到的人一定会有所收获的。
* 集合映射
如果实体类有一个集合类型的属性,就需要一张额外的表,即所谓的集合表,这
个表有一个外键引用实体类对应的表的主键。
根据集合中存放的元素类型可以分为两种: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 class="User"/>
</set>
这是做的双向关联,即从任何一方都可以得到另一方(User.getGroup得到所属的
组或Group.getUsers得到组中所有的用户);双方也都可以维护关系,维护关系
是指更新外键这一列的的值; 如果只有一方进行映射,就是单向关联。 如果去
掉了User.hbm.xml中的many-to-one映射,只有Group.hbm.xml中有一个set的映射,
这就是单向一对多关联,这时只能由Group维护关系,并且只能从Group得到User。
同样,如果只去掉Group.hbm.xml中的set映射,就是单向多对一关联。
树形结构,就是自己和自己是一个一对多的关系。如Group有父组和子组,映射文件
中为:
<many-to-one name="parent" column="parentId"/>
<set name="children">
<key column="parentId"/>
<!-- 集合中的元素还是Group -->
<one-to-many class="Group"/>
</set>
* 一对一映射:User与IdCard
有两种映射方式:基于主键和一对一和基于外键和一对一(用数据库说明)。不
管哪种方式,都是有外键的那个表对应的实体(IdCard)来维护关系;只为只有
IdCard能维护关系,所以如果要做单向关联,只能做从IdCard到User的单向关联。
不管是多对一还是一对一,有外键的那个表所对应的实体始终能够维护关系。
** 基于主键的一对一
在IdCard.hbm.xml中把主键生成策略改为foreign,并设置one-to-one:
...
<generator class="foreign">
<param name="property">user</param>
</generator>
...
one-to-one name="user" 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 class="Role" column="roleId"></many-to-many>
</set>
在Role.hbm.xml中增加:
<set name="groups" table="itcast_groups_roles">
<key column="roleId"></key>
<many-to-many class="Group" column="groupId"></many-to-many>
</set>
双方一定要在set元素中指定相同的表名(这是指定的中间表的名字)。元素
many-to-many 的class 属性用于指定关联类(集合中的实体元素)的名称;因为
是多对多,关联类在中间表中也是用一个外键指定的,many-to-many中的column
属性用于指定这个外键的列名。
这是做的双向关联,此时双方都可以维护关系。去掉任何一方的映射,就是单向
的双对多关联。
* 属性:lazy
延迟加载,默认值为true,即集合的属性值默认是不加载的。强制加载可以通过
在session环境中使用这个集合属性或者使用:Hibernate.initialize(proxy);
当相关联的session关闭后,再访问懒加载的对象将出现异常。
这些都是一些实体类:有Group,User,IdCard,Role
package cn.itcast.demo.entities;
import java.util.HashSet;
import java.util.Set;
public class Group {
private int id;
private String name;
private Set<User> users = new HashSet<User>();
private Group parent;
private Set<Group> children;
private Set<Role> roles = new HashSet<Role>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<User> getUsers() {
return users;
}
public void setUsers(Set<User> users) {
this.users = users;
}
public Group getParent() {
return parent;
}
public void setParent(Group parent) {
this.parent = parent;
}
public Set<Group> getChildren() {
return children;
}
public void setChildren(Set<Group> children) {
this.children = children;
}
public Set<Role> getRoles() {
return roles;
}
public void setRoles(Set<Role> roles) {
this.roles = roles;
}
}
package cn.itcast.demo.entities;
public class IdCard {
private int id;
private String sn;
private User user;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getSn() {
return sn;
}
public void setSn(String sn) {
this.sn = sn;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
package cn.itcast.demo.entities;
import java.util.HashSet;
import java.util.Set;
public class Role {
private int id;
private String name;
private Set<Group> groups = new HashSet<Group>();
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Set<Group> getGroups() {
return groups;
}
public void setGroups(Set<Group> groups) {
this.groups = groups;
}
}
package cn.itcast.demo.entities;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public class User implements java.lang.Comparable<User> {
private int id;
private String name;
private String desc;
private Date birthday;
private byte[] avatar;
private Set<String> addresses = new TreeSet<String>();
private String[] addresses2;
private List<String> addresses3 = new ArrayList<String>();
private List<String> phoneNumbers = new ArrayList<String>();
private int[] phoneNumbers2;
private Map<String, String> phoneNumbers3 = new HashMap<String, String>();
private Group group;
private IdCard idCard;
public User() {
}
public User(int id) {
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDesc() {
return desc;
}
public List<String> getAddresses3() {
return addresses3;
}
public void setAddresses3(List<String> addresses3) {
this.addresses3 = addresses3;
}
public void setDesc(String desc) {
this.desc = desc;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
public byte[] getAvatar() {
return avatar;
}
public void setAvatar(byte[] avatar) {
this.avatar = avatar;
}
public Set<String> getAddresses() {
return addresses;
}
public Map<String, String> getPhoneNumbers3() {
return phoneNumbers3;
}
public void setPhoneNumbers3(Map<String, String> phoneNumbers3) {
this.phoneNumbers3 = phoneNumbers3;
}
public void setAddresses(Set<String> addresses) {
this.addresses = addresses;
}
public List<String> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(List<String> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
public String[] getAddresses2() {
return addresses2;
}
public IdCard getIdCard() {
return idCard;
}
public void setIdCard(IdCard idCard) {
this.idCard = idCard;
}
public void setAddresses2(String[] addresses2) {
this.addresses2 = addresses2;
}
public int[] getPhoneNumbers2() {
return phoneNumbers2;
}
public void setPhoneNumbers2(int[] phoneNumbers2) {
this.phoneNumbers2 = phoneNumbers2;
}
public int compareTo(User o) {
return this.id - o.id;
}
public Group getGroup() {
return group;
}
public void setGroup(Group group) {
this.group = group;
}
@Override
public String toString() {
return new StringBuffer()//
.append("[User: id=").append(id) //
.append(",name=").append(name)//
.append("]")//
.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + id;
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final User other = (User) obj;
if (id != other.id)
return false;
return true;
}
}
这些都是一些实体类Group,User,IdCard,Role所对应的表。
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.demo.entities">
<class name="Group" table="itcast_group">
<id name="id" >
<generator class="native" />
</id>
<property name="name" type="string"/>
<!--
-->
<set name="users" >
<key column="groupId"></key>
<one-to-many class="User"/>
</set>
<many-to-one name="parent" column="parentId"/>
<set name="children">
<key column="parentId"/>
<one-to-many class="Group"/>
</set>
<set name="roles" table="itcast_groups_roles" lazy="true">
<key column="groupId"></key>
<many-to-many class="Role" column="roleId"></many-to-many>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.demo.entities">
<class name="IdCard" table="itcast_idcard">
<id name="id">
<generator class="native"></generator>
</id>
<property name="sn" type="string" />
<many-to-one name="user" column="userId" unique="true"></many-to-one>
<!-- 基于主键的一对一映射
<id name="id">
<generator class="foreign">
<param name="property">user</param>
</generator>
</id>
<one-to-one name="user" constrained="true"></one-to-one>
-->
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.demo.entities">
<class name="Role" table="itcast_role">
<id name="id">
<generator class="native" />
</id>
<property name="name" type="string" />
<set name="groups" table="itcast_groups_roles">
<key column="roleId"></key>
<many-to-many class="Group" column="groupId"></many-to-many>
</set>
</class>
</hibernate-mapping>
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="cn.itcast.demo.entities">
<class name="User" table="itcast_user">
<id name="id" unsaved-value="undefined">
<generator class="native" />
</id>
<property name="name" type="string" />
<property name="birthday" type="date" />
<property name="desc" column="desc_" type="text" />
<property name="avatar" length="512000" type="binary" />
<!--
<property name="avatar" >
<column name="avatar" sql-type="MEDIUMBLOB"/>
</property>
-->
<!--
<set name="addresses" table="itcast_user_addresses" order-by="address desc">
-->
<set name="addresses" table="itcast_user_addresses" sort="natural">
<key column="userId"></key>
<element type="string" column="address"></element>
</set>
<array name="addresses2" table="itcast_user_addresses2" >
<key column="userId"></key>
<list-index column="idx"></list-index>
<element type="string" column="address"></element>
</array>
<list name="phoneNumbers" table="itcast_user_phoneNumbers">
<key column="userId"></key>
<list-index column="idx"></list-index>
<element type="string" column="phoneNumber"></element>
</list>
<primitive-array name="phoneNumbers2" table="itcast_phoneNumbers2">
<key column="userId"></key>
<list-index column="idx"></list-index>
<element type="integer" column="phoneNumber"></element>
</primitive-array>
<bag name="addresses3" table="itcast_user_addresses3">
<key column="userId"></key>
<element type="string" column="address"></element>
</bag>
<map name="phoneNumbers3" table="itcast_user_phoneNumbers3">
<key column="userId"></key>
<map-key type="string" column="`key`"></map-key>
<element type="string" column="phoneNumber"></element>
</map>
<!--
-->
<many-to-one name="group" column="groupId" ></many-to-one>
<!-- 基于主键的一对一映射
<one-to-one name="idCard"></one-to-one>
-->
<one-to-one name="idCard" property-ref="user"></one-to-one>
</class>
</hibernate-mapping>