一:Hibernate映射集合属性
集合大致分为两种:
- 单列(List,Set,Array):Set比较特殊,因为它没有索引
- 多列(Map)
注:List集合可以用get(), Array可以用下标,Map集合可以用getKey()
1.1:映射集合属性之List
- 定义实体类,并描述其关系
- 引入核心配置文件
- 使用代码测试
1.1.1:定义实体类,并描述其关系
@Entity //将一个pojo,变成一个实体
@Table
public class Person {
@Id @Column(name="pid") //跟xml中name属性不一样,这里的name指定的是列名,因为属性名它可以通过注解知道的
@GeneratedValue(strategy = GenerationType.IDENTITY) //mysql中的主键自增长!
private Integer id;
private String name;
private Integer age;
@ElementCollection(targetClass = String.class) //指定集合中元素的类型
@CollectionTable(name = "school_inf",
joinColumns = @JoinColumn(name="pid",nullable = false)) //表示外键不能为空
@Column(name = "school_name") //指定表中保存集合元素的列名
@OrderColumn(name = "list_order") //索引列
private List<String> schools = new ArrayList<String>();
//省了getter/setter
}
1.1.2:引入核心配置文件
<mapping class="cn.itcast.mappingCollection.set.Person"/>
1.1.3:使用代码测试
@Test
public void testMappingList() {
Person person = new Person();
person.setName("wzj");
person.setAge(22);
person.getSchools().add("清华小学");
person.getSchools().add("北大中学");
person.getSchools().add("哈佛大学");
session.save(person);
//这里生成的school_inf表,会用pid和list_order作为联合主键,而且pid还会作为外键引用person的主键!
//如果生成表中的字段,和预想的完全不符,要看一下数据库中是否之前就存在该表,还有要注意hibernate核心配置文件是否有配置一样的表名导致的!
}
(1)生成表的SQL语句
CREATE TABLE `person` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `school_inf` (
`pid` int(11) NOT NULL,
`school_name` varchar(255) DEFAULT NULL,
`list_order` int(11) NOT NULL,
PRIMARY KEY (`pid`,`list_order`),
CONSTRAINT `FKq4nq3ibeg7pcb7jsvmlyetybx` FOREIGN KEY (`pid`) REFERENCES `person` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 注:其中pid作为外键,引用主表的主键, 并且pid,和list_order组成了一个复合主键
-- 复合主键:在一个表中由两个或两个以上的字段构成的主键,称为复合主键!
(2)生成的表记录
1.2:映射集合属性之Array
几乎和List的形式差不多!!
1.2.1:定义实体类,并描述其关系
@Entity
@Table
public class Student {
@Id @Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
private Integer age;
@ElementCollection(targetClass=String.class) //集合中元素的类型
@CollectionTable(name = "school",
joinColumns = @JoinColumn(name="sid",nullable = false))//指定外键的名称为sid,并且不能为空
@Column(name = "school_name") //指定schools属性,在表中的列名
@OrderColumn(name = "array_order")
private String[] schools = new String[3];
//省了getter/setter
}
1.2.2:引入核心配置文件
<mapping class="cn.itcast.mappingCollection.array.Student"/>
1.2.3:使用代码测试
@Test
public void testMappingList() {
Student student = new Student();
student.setName("wzj");
student.setAge(22);
String[] schools = student.getSchools();
schools[0] = "清华小学";
schools[1] = "北大中学";
schools[2] = "哈佛大学";
session.save(student);
}
(1)生成表的SQL语句
CREATE TABLE `student` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `school` (
`sid` int(11) NOT NULL,
`school_name` varchar(255) DEFAULT NULL,
`array_order` int(11) NOT NULL,
PRIMARY KEY (`sid`,`array_order`),
CONSTRAINT `FKrt2kife178gvxdtlor829pxut` FOREIGN KEY (`sid`) REFERENCES `student` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 注:使用school(从表)中的外键引用student(主表)中的主键
-- 注:sid即是外键, 也和array_order组成了一个复合主键
(2)生成的表记录
1.3:映射集合属性之Set
- 定义实体类,并描述其关系
- 引入到核心配置文件
- 使用代码测试
1.3.1:定义实体类,并描述其关系
@Entity
@Table(name = "person_Table")
public class Person {
@Id @Column(name="id")
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer pid;
private String name;
private Integer age;
@ElementCollection(targetClass = String.class) //指定集合元素的类型
@CollectionTable(name = "car_info",
joinColumns = @JoinColumn(name="pid",nullable = false))
@Column(name = "carName")
private Set<String> carNames = new HashSet<String>();
//省了getter/setter
}
1.3.2:引入到核心配置文件
<mapping class="cn.itcast.mappingCollection.set.Person"/>
1.3.3:使用代码测试
@Test
public void testMappingSet() {
Person person = new Person();
person.setName("wzj");
person.setAge(22);
person.getCarNames().add("保时捷");
person.getCarNames().add("兰博基尼");
person.getCarNames().add("法拉利");
session.save(person);
}
(1)生成表的SQL语句
CREATE TABLE `person_table` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `car_info` (
`pid` int(11) NOT NULL,
`carName` varchar(255) DEFAULT NULL,
KEY `FKryng6q8v9qp7d5e1mla7hc1g` (`pid`),
CONSTRAINT `FKryng6q8v9qp7d5e1mla7hc1g` FOREIGN KEY (`pid`) REFERENCES `person_table` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 注:因为Set集合没有索引,所以也不需要@OrderColumn,
-- 注:所以Set生成pid虽然即是主键又是外键,但不想List,Array那种的和索引列组成复合外键了!!
(2)生成的表记录
1.4:映射集合属性之Map
- 定义实体类,并描述其关系
- 引入到核心配置文件
- 使用代码测试
1.4.1:定义实体类,并描述其关系
@Entity
@Table(name = "t_stu")
public class Student {
@Id @Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
private Integer age;
@ElementCollection(targetClass = Float.class) //对于Map类型的属性:指定的是Value的类型
@CollectionTable(name = "score_info",
joinColumns = @JoinColumn(name="sid", nullable = false))
@MapKeyClass(String.class) //指定Map中key的类型
@MapKeyColumn(name="suject_name") //指定索引列,也就是key的列名
@Column(name = "score") //映射保存Map, Value的列名
private Map<String, Float> scores = new HashMap<String, Float>(); //科目和成绩
//省了getter/setter
}
1.4.2:引入到核心配置文件
<mapping class="cn.itcast.mappingCollection.map.Student"/>
1.4.3:使用代码测试
@Test
public void testMappingMap() {
Student student = new Student();
student.setName("wzj");
student.setAge(18);
student.getScores().put("数学", 20F);
student.getScores().put("语文", 80F);
student.getScores().put("英语", 80F);
session.save(student);
//复合主键:数据库表的主键由两个及以上的字段组成
//联合主键:多个主键联合形成一个主键的组合。多对多中的中间表就是的!!
}
(1)生成表的SQL语句
CREATE TABLE `t_stu` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `score_info` (
`sid` int(11) NOT NULL,
`score` float DEFAULT NULL,
`suject_name` varchar(255) NOT NULL,
PRIMARY KEY (`sid`,`suject_name`),
CONSTRAINT `FK54b26aem2wmdat88q1h7370bd` FOREIGN KEY (`sid`) REFERENCES `t_stu` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 和List和Array类似,因为都是有索引列的,Map的索引列就是key!!!
--- sid不仅是主键还是外键, 并且主键是和索引列组成复合主键!!!
(2)生成的表记录
1.4.4:上述总结:
-
不管哪种类型的集合属性,都需要使用@ElementCollection注解进行映射。
-
由于集合属性需要保存到另一个数据表,因此需要为这个表指定一个外键列,用于参照到主键列,
所以需要@CollectionTable注解映射保存集合属性的表,和@JoinColumn注解映射外键列
-
List,Array,Map有索引所以需要@OrderColumn或者@MapKeyColumn注解,Set没有所以不需要
-
有索引列的,一般都会和外键组成一个复合主键!!
二:Hibernate映射组件属性
什么是组件属性,你这里可以理解不是基本数据类型或包装类,或者String,Date这些。
这里的组件,就是指非持久化类的复合类型(可能还是不太理解,看看例子就知道了)
2.1:映射组件属性的方式一
2.1.1:定义实体类,并描述其关系
@Entity
@Table
public class People {
@Id @Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer pid;
private Integer age;
//组件属性: name
private Name name;
//省了getter/setter
}
@Embeddable //跟@Entity作用一样,表标识,表明这个Name是一个组件!
public class Name {
//@Column //这里不指定@Column也行,默认列名和属性名一致!
private String lastName;//姓
private String firstName;//名
@Parent //owner:主人的意思,@Parent指Name类这个组件,是所属People类的
private People owner;
public Name() {
super();
}
//省了getter和setter
}
2.1.2:引用到核心配置文件
<mapping class="cn.itcast.mappingComponent.映射组件属性.People"/>
2.1.3:使用代码测试
@Test
public void componentMappingMode1() {
People people = new People();
people.setName(new Name("大","帅b"));
people.setAge(22);
session.save(people);
}
(1)生成表的SQL语句
CREATE TABLE `people` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
`firstName` varchar(255) DEFAULT NULL,
`lastName` varchar(255) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
(2)生成的表记录
注:组件属性其实也什么特别的,就是把若干个属性封装成一个,到映射的时候再拆分出来!
2.1.4:映射组件属性的方式二
@Entity
@Table
public class People2 {
@Id @Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer pid;
private Integer age;
//组件属性: name
@AttributeOverrides({
@AttributeOverride(name="lastName", column = @Column(name="lastName")),
@AttributeOverride(name="firstName", column = @Column(name="firstName"))
})
private Name name;
//省了getter/setter
}
@Embeddable
public class Name {
// @Column //这里不指定@Column也行,默认列名和属性名一致!
private String lastName;//姓
private String firstName;//名
@Parent
private People owner;
public Name() {
super();
}
//添加有参构造只是为了好赋值而已
public Name(String lastName, String firstName) {
super();
this.lastName = lastName;
this.firstName = firstName;
}
//省了getter/setter
}
(1)生成表的SQL语句
CREATE TABLE `people2` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
`firstName` varchar(255) DEFAULT NULL,
`lastName` varchar(255) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
(2)生成的表记录
注:生成表的SQL语句和记录,和方式一,一模一样。这样方式适合组件中属性较少的场景
2.2:组件属性中有集合
2.2.1:定义实体类,并描述其关系
@Entity
@Table(name = "t_people")
public class People {
@Id @Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer pid;
private Integer age;
//组件属性
private Name name;
//省了getter/setter
}
@Embeddable
public class Name {
private String lastName;
private String firstName;
@Parent
private People owner; //owner:主人的意思, 使用@Parent注解标识
//组件属性为集合: 这个maps属性没有什么含义,就是单纯演示一下这种效果
@CollectionTable(name="demoInfo",
joinColumns = @JoinColumn(name="person_name_id", nullable = false))
@MapKeyClass(String.class) //指定Map类型中key的类型
@ElementCollection(targetClass = Integer.class) //对于Map类型来说,targetClass指的是value的类型
@MapKeyColumn(name="demo_key") //映射Map中key
@Column(name="demo_value") //映射Map中的Value
private Map<String, Integer> demo = new HashMap<String, Integer>();
public Name() {
super();
}
//只是为了快速赋值
public Name(String lastName, String firstName) {
super();
this.lastName = lastName;
this.firstName = firstName;
}
}
2.2.2:引入到核心配置文件
<mapping class="cn.itcast.mappingComponent.组件属性中有集合.People"/>
2.2.3:使用代码测试
@Test
public void componentMapping() {
Map<String, Integer> map = new HashMap<String, Integer>();
map.put("key1", 100);
map.put("key2", 200);
Name name = new Name("大", "帅B");
name.setDemo(map);
People people = new People();
people.setAge(22);
people.setName(name);
session.save(people);
}
(1)生成表的SQL语句
CREATE TABLE `t_people` (
`pid` int(11) NOT NULL AUTO_INCREMENT,
`age` int(11) DEFAULT NULL,
`firstName` varchar(255) DEFAULT NULL,
`lastName` varchar(255) DEFAULT NULL,
PRIMARY KEY (`pid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
-- 把组件属性中一些基本数据类型的属性,引入过来了,由于集合会生成另外一张表,因此会使用外键来引入本表的主键
CREATE TABLE `demoinfo` (
`person_name_id` int(11) NOT NULL,
`demo_value` int(11) DEFAULT NULL,
`demo_key` varchar(255) NOT NULL,
PRIMARY KEY (`person_name_id`,`demo_key`),
CONSTRAINT `FKdjlg9hxfscnb38ye0ymjyqg9x` FOREIGN KEY (`person_name_id`) REFERENCES `t_people` (`pid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 组件中的集合属性,最终生成了另一张表
-- person_name_id即是主键也是外键,并且和Map的索引列,成为了一个复合主键!
(2)生成的表记录
2.3:集合的元素是组件
2.3.1:定义实体类,并描述其关系
@Entity
@Table(name = "t_student")
public class Student {
@Id @Column
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer sid;
private String name;
@CollectionTable(name = "t_car",
joinColumns = @JoinColumn(name="sid", nullable = false))
@ElementCollection(targetClass = Car.class)
@OrderColumn(name = "list_order")
// @Column 如果映射元素是组件属性,那么就不用@Column
private List<Car> cars = new ArrayList<Car>();//组件属性
@CollectionTable(name = "t_score",
joinColumns = @JoinColumn(name="sid", nullable = false))
@MapKeyClass(String.class) //Map中Key的类型
@ElementCollection(targetClass = Score.class) //Map中Value的类型
@MapKeyColumn(name="subject")
// @Column 如果映射元素是组件属性,那么就不用@Column
private Map<String, Score> scoreMap = new HashMap<String, Score>();//组件属性
//省了getter/setter方法
}
组件属性Car:
@Embeddable
public class Car {
private String carName;
private String color;
@Parent
private Student owner;
public Car() {
super();
}
}
组件属性Score:
@Embeddable
public class Score {
private String level; //分数的级别:优秀, 良好, 不及格
private String ranking; //分数的排名
@Parent
private Student owner; //这个Score组件,属于哪个实体!
public Score() {
super();
}
//只是为了好赋值
public Score(String level, String ranking) {
super();
this.level = level;
this.ranking = ranking;
}
}
2.3.2:引入到核心配置文件
<mapping class="cn.itcast.mappingComponent.集合属性的元素为组件.Student"/>
2.3.3:使用代码测试
@Test
public void componentMapping() {
Map<String,Score> scoreMap = new HashMap<String,Score>();
scoreMap.put("数学", new Score("不及格", "倒数"));
scoreMap.put("英语", new Score("不及格", "倒数"));
List<Car> cars = new ArrayList<Car>();
cars.add(new Car("魅影","粉红色"));
cars.add(new Car("阿斯顿马丁","粉红色"));
Student student = new Student();
student.setName("wzj");
student.setScoreMap(scoreMap);
student.setCars(cars);
session.save(student);
}
(1)生成表的SQL语句
CREATE TABLE `t_student` (
`sid` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) DEFAULT NULL,
PRIMARY KEY (`sid`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8
CREATE TABLE `t_car` (
`sid` int(11) NOT NULL,
`carName` varchar(255) DEFAULT NULL,
`color` varchar(255) DEFAULT NULL,
`list_order` int(11) NOT NULL,
PRIMARY KEY (`sid`,`list_order`),
CONSTRAINT `FKh832i1jgopvw91lwl2x3q49tt` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 注:sid即是主键也是外键,因为List集合有索引列,所以sid和索引列(list_order)组成了一个复合主键
-- 注:集合的元素是组件的话,那么集合会生成一张表,而组件中的属性会存到集合生成的表中 !!!
CREATE TABLE `t_score` (
`sid` int(11) NOT NULL,
`level` varchar(255) DEFAULT NULL,
`ranking` varchar(255) DEFAULT NULL,
`subject` varchar(255) NOT NULL,
PRIMARY KEY (`sid`,`subject`),
CONSTRAINT `FKig6ef2hkc758ki6vqxuvqf5ay` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 类似, sid即是外键也是主键,因为Map也有索引列那就是它的key,所以主键和索引列也会组成一个复合主键
-- 同理:集合的元素是组件的话,那么集合会生成一张表,而组件中的属性会存到集合生成的表中 !!!
(2)生成的表记录
),
CONSTRAINT FKh832i1jgopvw91lwl2x3q49tt
FOREIGN KEY (sid
) REFERENCES t_student
(sid
)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
– 注:sid即是主键也是外键,因为List集合有索引列,所以sid和索引列(list_order)组成了一个复合主键
– 注:集合的元素是组件的话,那么集合会生成一张表,而组件中的属性会存到集合生成的表中 !!!
```sql
CREATE TABLE `t_score` (
`sid` int(11) NOT NULL,
`level` varchar(255) DEFAULT NULL,
`ranking` varchar(255) DEFAULT NULL,
`subject` varchar(255) NOT NULL,
PRIMARY KEY (`sid`,`subject`),
CONSTRAINT `FKig6ef2hkc758ki6vqxuvqf5ay` FOREIGN KEY (`sid`) REFERENCES `t_student` (`sid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
-- 类似, sid即是外键也是主键,因为Map也有索引列那就是它的key,所以主键和索引列也会组成一个复合主键
-- 同理:集合的元素是组件的话,那么集合会生成一张表,而组件中的属性会存到集合生成的表中 !!!
(2)生成的表记录
最后来自:虽然帅,但是菜的cxy