Hibernate高级映射——集合映射
一 概念
1.集合类型的作用
在持久化类中,有时会使用到值类型的对象属性,所谓值类型的对象,是指它对应的类没有对象标识符属性,只能作为一个持久化类的属性使用。如果持久化类中一个值类型的集合,那么就需要一张额外的数据库表来保存这个值类型集合的数据,这张表被称为集合表。
2.集合接口的种类
(1)<set>元素:可以映射类型为java.util.Set接口的属性,它的元素存放没有顺序且不允许重复,也可以映射类型为java.util.SortSet接口的属性,它的元素可以按自然属性排序
(2)<list>元素:可以映射类型为java.util.List接口的属性,它需要在结合属性对象的数据库表中用一个额外的索引列保存每一个元素的位置,即是有属性可重复的。
(3)<bag>元素:可以映射java.util.Collection接口的属性,它的元素可能重复,但不保存属性,和set差不多,正因为有它,是因为如果通常使用list比较多,并且不想让添加一列的话,就用它。
(4)<map>元素:可以映射为java.util.Map接口的属性,它的元素以键值对的形式保存,也是无序的,也可以映射类型为java.util.SortMap接口的属性,它的元素可以按自然顺序排序。
(5)<array>元素:可以映射类型为数组的属性,但在实际运用中用的极少
3.注意
(1)在java的实体类中集合只能定义成接口不能定义成实现类
(2)这些集合类都是Hibernate实现的类和JAVA中的集合类不完全一样,set,list,map分别和JAVA中的Set,List,Map接口对应,bag映射成JAVA的List;这些集合的使用和JAVA集合中对应的接口基本一致;在JAVA的实体类中集合只能定义成接口不能定义成具体类, 因为集合会在运行时被替换成Hibernate的实现。
4.集合的简单使用原则
大部分情况下用set,需要保证集合中的顺序用list,想用java.util.List又不需要保证顺序用bag。
二 代码分析
映射set
1.Student实体类
package com.hbsi.domain;
import java.util.Set;
public class Student {
private int id;
private String name;
private Set<String> hobbies;//爱好 集合对象
public Student() {
super();
// TODO Auto-generated constructor stub
}
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<String> getHobbies() {
return hobbies;
}
public void setHobbies(Set<String> hobbies) {
this.hobbies = hobbies;
}
}
2.Student.hbm.xml映射表
<?xml version="1.0"?>
<!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.hbsi.domain">
<class name="Student" table="student">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" />
<set name="hobbies" table="student_hobby">
<key column="student_id"></key>
<element type="string" column="hobbies_name"></element>
</set>
</class>
</hibernate-mapping>
注:Set类型集合的特点:它的元素存放没有顺序而且不允许重复,如插入的是两个相同的字段,会看成是一个,在set中最重要的是在映射表中的:
<set name="hobbies" table="student_hobby">
<key column="student_id"></key>
<element type="string" column="hobbies_name"></element>
</set>
其中key是stuent_hobby的外键,element元素标签是映射到数据库中的集合的字段
3.使用插入语句持久化操作
package com.hbsi.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.hbsi.domain.Student;
import com.hbsi.hibernate.utils.HibernateUtil;
public class TestSet {
public static void main(String[] args) {
add();
}
static void add() {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
//添加
Student student = new Student();
student.setName("熊熊");
Set<String> hobbies = new HashSet<String>();
hobbies.add("睡觉");
hobbies.add("吃");
hobbies.add("玩");
student.setHobbies(hobbies);
session.save(student);
transaction.commit();
} finally {
if (session != null) {
session.close();
}
}
}
}
映射list
1.Student实体类类
package com.hbsi.domain;
import java.util.List;
import java.util.Set;
public class Student {
private int id;
private String name;
private List<String> hobbies;
public Student() {
super();
// TODO Auto-generated constructor stub
}
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 List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
}
2.Student.hbm.xml映射
<?xml version="1.0"?>
<!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.hbsi.domain">
<class name="Student" table="student">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" />
<list name="hobbies" table="student_hobby1">
<key column="student_id"></key>
<!-- 指定索引列 维护元素的添加顺序 只在关系模型中有效 -->
<list-index column="order_index"></list-index>
<element type="string" column="hobbies_name"></element>
</list>
</class>
</hibernate-mapping>
3.使用插入语句持久化操作
package com.hbsi.test;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.hbsi.domain.Student;
import com.hbsi.hibernate.utils.HibernateUtil;
public class TestSet {
public static void main(String[] args) {
add();
}
static void add() {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
//添加
Student student = new Student();
student.setName("熊熊");
List<String> hobbies = new ArrayList<String>();
hobbies.add("睡觉");
hobbies.add("吃");
hobbies.add("吃");
student.setHobbies(hobbies);
session.save(student);
transaction.commit();
} finally {
if (session != null) {
session.close();
}
}
}
}
因为在list集合中,会多一条,如果不希望维护添加的顺序,在原有的基础上把映射文件中的list标签改成bag,如下:
<?xml version="1.0"?>
<!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.hbsi.domain">
<class name="Student" table="student">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" />
<!-- bag标签不需要维护顺序 -->
<bag name="hobbies" table="student_hobby2">
<key column="student_id"></key>
<element type="string" column="hobbies_name"></element>
</bag>
</class>
</hibernate-mapping>
映射Map
1.Student实体类
package com.hbsi.domain;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Student {
private int id;
private String name;
private Map<Long, String> hobbies;
public Student() {
super();
// TODO Auto-generated constructor stub
}
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 Map<Long, String> getHobbies() {
return hobbies;
}
public void setHobbies(Map<Long, String> hobbies) {
this.hobbies = hobbies;
}
}
2.Student.hbm.xml映射文件
<?xml version="1.0"?>
<!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.hbsi.domain">
<class name="Student" table="student">
<id name="id" column="id">
<generator class="native" />
</id>
<property name="name" column="name" />
<map name="hobbies" table="student_hobbies3">
<key column="student_id"></key>
<!-- 指定map属性的键在对应表中的列 外键的列 key -->
<map-key type="long" column="hobbies_id"></map-key>
<!-- 键值对的值 value -->
<element type="string" column="hobbies_name"></element>
</map>
</class>
</hibernate-mapping>
3.使得插入语句持久化
package com.hbsi.test;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.hbsi.domain.Student;
import com.hbsi.hibernate.utils.HibernateUtil;
public class TestSet {
public static void main(String[] args) {
add();
}
static void add() {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.beginTransaction();
//添加
Student student = new Student();
student.setName("熊熊");
Map<Long, String> hobbies = new HashMap<Long, String>();
hobbies.put(new Long(1001),"football");
hobbies.put(new Long(1002), "dance");
student.setHobbies(hobbies);
session.save(student);
transaction.commit();
} finally {
if (session != null) {
session.close();
}
}
}
}
注:
(1)如果对象模型用的是set类型的集合,映射文件用的是set标签
(2)如果对象模型用的是list集合,如果想维护元素的顺序,单独向表中添加一列,可用list标签
(3)如果对象模型用的是list集合,不希望维护添加的顺序,没有单独的一列,可以用bag标签
(4)如果对象模型是Map集合,用到的是map标签进行映射
(5)String[]数组需要用下标来维护,和list相似
(6)List集合在映射的时候单独多了一列是为了维护添加的顺序,可以有重复性