集合属性
集合属性只声明接口。
不管什么集合属性,都需要@ElementCollection
注解进行映射,该注解有2个属性:
- fetch
: 指定该实体对集合属性的抓取策略。有2种,分别是FetchType.LAZY
,FetchType.EAGER
,前者标识延迟加载,后者为立即加载。
- targetClass
: 指定集合属性中集合元素的类型。
集合属性需要保存在另外一张表中,举个例子: 一个毕业生,他上完了小学、初中、高中、大学,那这4个学校级别都是属于同一个集合的,也就是说一个人对应一个属性的多个值。所以可以把这些值放在另一个表中,该表中必须包含一个外键列,这样才能根据原始表中的主键值找到另一个数据表的数据。该外键连使用@JoinColumn
注解修饰。
CollectionTable
注解指定映射保存集合属性的表。
对于List
、数组集合,是有序的,可以使用@OrderColumn
注解,用户定义List
、数组的索引列,指定顺序。
对于Map
集合,使用key
作为集合元素的索引,可以使用@MapKeyColumn
注解,用于映射Map
集合索引列。
1. List
集合属性映射
现有一个Person
类,它有一个集合: schools
,该属性对应多个学校。由于集合属性只能声明接口,所以schools
类型只能是List
,而不是ArrayList
,但是该属性必须使用对应实现的类初始化。对于List
,需要实例化ArrayList
或实现List
接口的类。
//使用JPA规范的主键生成策略
@Entity
@Table(name = "person_inf")
public class Person_list {
@Id
@Column(name = "person_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int age;
//指定集合的抓取策略为延迟抓取(默认为lazy),指定集合元素的类型
@ElementCollection(fetch = FetchType.LAZY, targetClass = String.class)
//映射保存集合属性的表
@CollectionTable(name = "school_inf",
joinColumns = @JoinColumn(name = "person_id", nullable = false))
//指定保存集合元素的列为 school_name
@Column(name = "school_name")
//映射集合元素索引的列
@OrderColumn(name = "list_order")
private List<String> schools = new ArrayList<>();
//省略get、set
...
}
@ElementCollection(fetch = FetchType.LAZY, targetClass = String.class)
表示获取该集合元素使用延迟(默认就是延迟),集合元素类型为String
。@CollectionTable(name = "school_inf", joinColumns = @JoinColumn(name = "person_id", nullable = false))
表示集合映射表名为school_inf
,映射的一个外键列名为person_id
,不能为空。如果原表中主键有多个,映射表需要指定对应数量的外键列。@Column(name = "school_name")
: 指定映射表存放元素值的名称。@OrderColumn(name = "list_order")
: 用于映射表的索引列名,用来排序。
测试代码:
session.beginTransaction();
Person_list personList = new Person_list();
personList.setName("sweat1");
personList.setAge(21);
personList.getSchools().add("小学");
personList.getSchools().add("中学");
personList.getSchools().add("高中");
personList.getSchools().add("大学");
session.save(personList);
session.getTransaction().commit();
数据库数据:
mysql> select * from person_inf;
+-----------+-----+--------+
| person_id | age | name |
+-----------+-----+--------+
| 1 | 21 | sweat1 |
+-----------+-----+--------+
1 row in set (0.00 sec)
mysql> select * from school_inf;
+-----------+-------------+------------+
| person_id | school_name | list_order |
+-----------+-------------+------------+
| 1 | 小学 | 0 |
| 1 | 中学 | 1 |
| 1 | 高中 | 2 |
| 1 | 大学 | 3 |
+-----------+-------------+------------+
4 rows in set (0.00 sec)
2. 数组映射
数组和List
非常相似,所以使用上也基本相同,直接给出代码。
Person
类
@Entity
@Table(name = "person_inf")
public class Person_Arr {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int age;
@ElementCollection(fetch = FetchType.LAZY, targetClass = String.class)
@CollectionTable(name = "school_inf",
joinColumns = @JoinColumn(name = "person_id", nullable = false))
@Column(name = "school_name")
@OrderColumn(name = "array_order")
private String[] schools;
//省略get、set
...
}
测试代码:
session.beginTransaction();
Person_Arr personArr = new Person_Arr();
personArr.setName("sweat");
personArr.setAge(21);
String[] str = {"小学", "初中", "高中", "大学"};
personArr.setSchools(str);
session.save(personArr);
session.getTransaction().commit();
数据库数据:
mysql> select * from person_inf;
+----+-----+-------+
| id | age | name |
+----+-----+-------+
| 1 | 21 | sweat |
+----+-----+-------+
1 row in set (0.00 sec)
mysql> select * from school_inf;
+-----------+-------------+-------------+
| person_id | school_name | array_order |
+-----------+-------------+-------------+
| 1 | 小学 | 0 |
| 1 | 初中 | 1 |
| 1 | 高中 | 2 |
| 1 | 大学 | 3 |
+-----------+-------------+-------------+
4 rows in set (0.00 sec)
3. set集合映射
set
集合和之前的List
、数组有一个不同,set
集合时无序、不重复的,所以set
不需要@OrderColumn
注释。和List
一样,应该声明接口。
Person
类:
@Entity
@Table(name = "person_inf")
public class Person_set {
@Id
@Column(name = "person_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int age;
@ElementCollection(targetClass = String.class, fetch = FetchType.LAZY)
@CollectionTable(name = "school_inf",
joinColumns = @JoinColumn(name = "person_id", nullable = false))
@Column(name = "school_name", nullable = false)
private Set<String> schools = new HashSet<>();
//省略get、set、构造函数
...
}
测试代码:
session.beginTransaction();
Person_set personSet = new Person_set();
personSet.setName("sweat");
personSet.setAge(21);
Set<String> set = new HashSet<>();
set.add("小学");
set.add("高中");
set.add("初中");
set.add("大学");
personSet.setSchools(set);
session.save(personSet);
session.getTransaction().commit();
数据库数据:
mysql> select * from person_inf;
+-----------+-----+-------+
| person_id | age | name |
+-----------+-----+-------+
| 1 | 21 | sweat |
+-----------+-----+-------+
1 row in set (0.00 sec)
mysql> select * from school_inf;
+-----------+-------------+
| person_id | school_name |
+-----------+-------------+
| 1 | 初中 |
| 1 | 大学 |
| 1 | 小学 |
| 1 | 高中 |
+-----------+-------------+
4 rows in set (0.00 sec)
4. Map
集合映射
Map
属性映射也需要使用@ElementCollection
映射集合,使用CollectionTable
来指定映射表信息,还需要使用@MapKeyColumn
注解指定Map
的key
的数据列名。Hibernate
同时会将外键列和key
列作为联合主键。
Person
类:
@Entity
@Table(name = "person_inf")
public class Person_Map {
@Id
@Column(name = "person_id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String name;
private int age;
@ElementCollection(fetch = FetchType.LAZY, targetClass = Float.class)
@CollectionTable(name = "score_inf",
joinColumns = @JoinColumn(name = "person_id", nullable = false))
@MapKeyColumn(name = "key_col")
@MapKeyClass(String.class)
@Column(name = "value_col")
private Map<String, Float> scores = new HashMap<>();
//省略get、set、构造函数
...
}
@ElementCollection(fetch = FetchType.LAZY, targetClass = Float.class)
和其它一样。@CollectionTable(name = "score_inf", joinColumns = @JoinColumn(name = "person_id", nullable = false))
指定映射表名,指定外键列名,非空。@MapKeyColumn(name = "key_col")
:指定映射表中Map
的key
列名。@MapKeyClass(String.class)
: 指定映射表中Map
的key
数据类型。@Column(name = "value_col")
: 指定映射表中Map
的value
列名。
测试代码:
session.beginTransaction();
Person_Map personMap = new Person_Map();
personMap.setName("sweat");
personMap.setAge(21);
Map<String, Float> mp = new HashMap<>();
mp.put("key1", 1.5f);
mp.put("key2", 2.5f);
mp.put("key4", 3.5f);
mp.put("key3", 4.5f);
personMap.setScores(mp);
session.save(personMap);
session.getTransaction().commit();
数据库数据:
先看person_inf
表描述:
mysql> desc person_inf;
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| person_id | int(11) | NO | PRI | NULL | auto_increment |
| age | int(11) | NO | | NULL | |
| name | varchar(255) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
3 rows in set (0.00 sec)
score_inf
表描述:
mysql> desc score_inf;
+-----------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+-------+
| person_id | int(11) | NO | PRI | NULL | |
| value_col | float | YES | | NULL | |
| key_col | varchar(255) | NO | PRI | NULL | |
+-----------+--------------+------+-----+---------+-------+
3 rows in set (0.00 sec)
插入的数据:
mysql> select * from person_inf;
+-----------+-----+-------+
| person_id | age | name |
+-----------+-----+-------+
| 1 | 21 | sweat |
+-----------+-----+-------+
1 row in set (0.00 sec)
mysql> select * from score_inf;
+-----------+-----------+---------+
| person_id | value_col | key_col |
+-----------+-----------+---------+
| 1 | 1.5 | key1 |
| 1 | 2.5 | key2 |
| 1 | 4.5 | key3 |
| 1 | 3.5 | key4 |
+-----------+-----------+---------+
4 rows in set (0.00 sec)