继承关系映射和集合映射
1.继承关系映射
Hibernate 允许将继承关系保存到数据库中
三种继承映射策略
第一种 subclass 父类和子类数据用同一张表保存,引入辨别者列,区分数据是父类数据还是子类数据
第二种 join-subclass 父类和子类 数据都是单独一张表,表之间通过外键表示继承关系
第三种 unions-subclass(了解 ) 父类和子类 都是单独一张表,表之间没有任何联系
1)subclass 元素的继承映射
父类数据 和 子类数据 存放一张表,引入一列 辨别者列(区分数据是否父类还是子类)
①编写 Employee、HourEmployee、SalaryEmployee
public class Employee {
private Integer id;
private String name;
……省略setter和getter方法
}
// 小时工
public class HourEmployee extends Employee {
private Double rate; // 时薪
public Double getRate() {
- ……省略setter和getter以及toString方法
}
// 正式员工
public class SalaryEmployee extends Employee {
private Double salary;
- ……省略setter和getter方法
}
②在继承关系模型中,只需要对父类编写
hbm
映射就可以了
<hibernate-mapping>
<class name="cn.itcast.subclass.Employee" table="employee" catalog="hibernate3day4" discriminator-value="ee">
<id name="id">
<generator class="identity"></generator>
</id>
<!-- 定义辨别者列 -->
<!-- 该列主要给Hibernate框架使用 -->
<discriminator column="etype"></discriminator>
<property name="name"></property>
<!-- 每个子类 使用 subclass元素配置 -->
<subclass name="cn.itcast.subclass.HourEmployee" discriminator-value="he">
<property name="rate"></property>
</subclass>
<subclass name="cn.itcast.subclass.SalaryEmployee" discriminator-value="se">
<property name="salary"></property>
</subclass>
</class>
</hibernate-mapping>
测试添加和查询
@Test
// 插入一些数据
public void demo1() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 保存员工
Employee employee = new Employee();
employee.setName("张三");
session.save(employee);
// 保存小时工
HourEmployee hourEmployee = new HourEmployee();
hourEmployee.setName("李四");
hourEmployee.setRate(10d);
session.save(hourEmployee);
// 保存正式员工
SalaryEmployee salaryEmployee = new SalaryEmployee();
salaryEmployee.setName("王五");
salaryEmployee.setSalary(3000d);
session.save(salaryEmployee);
transaction.commit();
}
进入数据库查看数据:
我们发现,这样就把父子类的数据存到一张表里面了!
进行查询
@Test
// 查询
public void demo2() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
// 查询所有小时工
List<HourEmployee> hourEmployees = session.createQuery(
"from HourEmployee").list();
System.out.println(hourEmployees);
transaction.commit();
}
2)joined-subclass 元素的继承映射
为父类数据和子类数据分别建表,公共信息放入父类表,个性信息放入子类表,通过外键关联
*** 使用继承映射,类关系是不变的 【上面4个Java文件的内容是不需要改动的!】
<hibernate-mapping>
<class name="cn.itcast.joinedsubclass.Employee" table="employee" catalog="hibernate3day4" >
<id name="id">
<generator class="identity"></generator>
</id>
<property name="name"></property>
<!-- 为每个子类表编写 joined-subclass 元素 -->
<joined-subclass name="cn.itcast.joinedsubclass.HourEmployee" table="h_employee">
<!-- 配置子类表 外键 -->
<!-- eid 是 子类表主键,同时也是外键,引入父类表 id -->
<key column="eid"></key>
<property name="rate"></property>
</joined-subclass>
<joined-subclass name="cn.itcast.joinedsubclass.SalaryEmployee" table="s_employee">
<key column="eid"></key>
<property name="salary"></property>
</joined-subclass>
</class>
</hibernate-mapping>
***
优先使用
joined-subclass,
如果类信息非常少,也可以使用
subclass
2.集合映射
在hbm文件中使用<set>配置一对多和多对多(set集合是无序不允许重复的),在实际开发中,经常会使用有序的集合List(有序,可重复)
配置方式有<bag> <list> <set>等,而<bag>是基于list的,在javabean中我们继续使用list进行关系维护,只需要在配置的时候使用<bag>即可。<bag>的效率最高!它是无序,可重复的。
<bag>示例:
JavaBean:Article.java
public class Article {
private Integer id;
private String title;
private Author author;
- setter&getter……
- }
映射文件:Article.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.collectionmapping.Article" table="article">
<id name="id">
<generator class="identity"></generator>
</id>
<property name="title"></property>
<!-- 多对一 -->
<many-to-one name="author" class="cn.itcast.collectionmapping.Author" column="author_id"></many-to-one>
</class>
</hibernate-mapping>
JavaBean:Author.java
// 作者
public class Author {
private Integer id;
private String name;
private List<Article> articles = new ArrayList<Article>();
- setter&getter……
}
映射文件:Author.hbm.xml
<hibernate-mapping>
<class name="cn.itcast.collectionmapping.Author" table="author">
<id name="id">
<generator class="identity"></generator>
</id>
<property name="name"></property>
<!-- 一对多 -->
<bag name="articles" cascade="all">
<key column="author_id"></key>
<one-to-many class="cn.itcast.collectionmapping.Article"/>
</bag>
</hibernate-mapping>
最后在hibernate.cfg.xml文件中进行配置
<mapping resource="cn/itcast/collectionmapping/Author.hbm.xml"/>
<mapping resource="cn/itcast/collectionmapping/Article.hbm.xml"/>
进行测试:
@Test
// 插入一个作者,两篇文章
public void demo1() {
Session session = HibernateUtils.getCurrentSession();
Transaction transaction = session.beginTransaction();
Author author = new Author();
author.setName("金庸");
Article article = new Article();
article.setTitle("天龙八部");
Article article2 = new Article();
article2.setTitle("笑傲江湖");
author.getArticles().add(article);
author.getArticles().add(article2);
session.save(author);
transaction.commit();
}
至此,bag的操作结束,它其实和list的操作没啥很大区别。
问题:为什么list的操作就有序了呢?
原理:在数据表中保存数据下标(维护有序性 )
上面的代码不需要改动,只需要在映射文件Author.hbm.xml文件中修改配置即可
<hibernate-mapping>
<class name="cn.itcast.collectionmapping.Author" table="author">
<id name="id">
<generator class="identity"></generator>
</id>
<property name="name"></property>
<list name="articles" cascade="all">
<key column="author_id"></key>
<!-- 生成列,article_index 维护顺序 -->
<list-index column="article_index"></list-index>
<one-to-many class="cn.itcast.collectionmapping.Article"/>
</list>
</class>
</hibernate-mapping>
简单的说就是多了一列来维护顺序,我们可以查看最后数据库查询的结果:
+----+----------+-----------+---------------+
| id | title | author_id | article_index |
+----+----------+-----------+---------------+
| 1 | 天龙八部 | 1 | 0 |
| 2 | 笑傲江湖 | 1 | 1 |
+----+----------+-----------+---------------+