1. Employee 为基类, 派生出HourEmployee 和 SalaryEmployee两个类。
采用 subclass 元素的继承映射(1)
采用
subclass
的继承映射可以实现
对于继承关系中
父类和子类使用同一张表
因为父类和子类的实例全部保存在同一个表中,因此
需要在该表内增加一列
,使用该列来区分每行记录到底是哪个类的实例
----
这个列被称为辨别者列
(
discriminator
).
在这种映射策略下,
使用
subclass
来映射子类
,
使用
class
或
subclass
的
discriminator-value
属性指定辨别者列的值
所有子类定义的字段都不能有非空约束
。如果为那些字段添加非空约束,那么父类的实例在那些列其实并没有值,这将引起数据库完整性冲突,导致父类的实例无法保存到数据库中
示例代码::
Employee.java
public class Employee {
private Integer id;
private String name;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
HourEmployee.java
/**
* 钟点工
*/
public class HourEmployee extends Employee{
private Double rate;
public Double getRate() {
return rate;
}
public void setRate(Double rate) {
this.rate = rate;
}
}
SalaryEmployee.java
/**
* 正是员工
*/
public class SalaryEmployee extends Employee {
private Double salary;
public Double getSalary() {
return salary;
}
public void setSalary(Double salary) {
this.salary = salary;
}
}
Employee.hbm.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.itcast.extends01.Employee" table="employee" discriminator-value="ee">
<id name="id" type="integer">
<column name="id"/>
<generator class="increment"/>
</id>
<!--辨别者列,column="etype"用于区分员工的种类,该配置必须放置在id的后面-->
<discriminator column="etype" type="string"/>
<property name="name" type="string">
<column name="name"/>
</property>
<!--配置子类
discriminator-value: 子类对应的辨别者列的值
-->
<subclass name="cn.itcast.extends01.HourEmployee" discriminator-value="he">
<property name="rate" column="rate" type="double"/>
</subclass>
<subclass name="cn.itcast.extends01.SalaryEmployee" discriminator-value="se">
<property name="salary" column="salary" type="double"/>
</subclass>
</class>
</hibernate-mapping>
App.java
public class App {
private static SessionFactory sf=null;
static{
Configuration config=new Configuration();
config.configure("cn/itcast/extends01/hibernate.cfg.xml");
config.addClass(Employee.class);
sf=config.buildSessionFactory();
}
/*
* 知识点1: 保存员工信息
*/
@Test
public void saveStudentAndCoure(){
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
Employee e=new Employee();
e.setName("xxxx");
HourEmployee he=new HourEmployee();
he.setName("小昭");
he.setRate(10d);
SalaryEmployee se=new SalaryEmployee();
se.setName("赵敏");
se.setSalary(3000d);
session.save(e);
session.save(he);
session.save(se);
tx.commit();
session.close();
}
//知识点2: 查询钟点工信息
@Test
public void findHourEmployee(){
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
//HQL语句 可以使用子类HourEmployee
Query query=session.createQuery("from HourEmployee");
query.list();
tx.commit();
session.close();
}
}
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/test</property>
<!-- 配置数据库的方言,让hibernate知道连接的是哪个数据库-->
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- 配置利用javaBean和映射文件生成数据库中的表
hibernate.hbm2ddl.auto值
* create:执行时,先查找该表是否存在,如存在先删除表,在创建表
* none:不能创建表,只能往表中插入数据,如表不存在抛出异常,默认值
* update:执行时,
情况一:
先查找该表是否存在,如果表存在,直接插入,如果表不存在,先创建表,再插入数据.
情况二:
先查找该表是否存在,如果表存在,但表的结构不一样,要修改表的结构
-->
<property name="hibernate.hbm2ddl.auto">update</property>
<!-- 显示hibernate生成的sql语句 -->
<property name="hibernate.show_sql">true</property>
<!-- 显示格式化得sql语句 -->
<property name="hibernate.format_sql">false</property>
</session-factory>
</hibernate-configuration>
采用 joined-subclass 元素的继承映射(2)
采用
joined-subclass
元素的继承映射可以
实现每个子类一张表
采用这种映射策略时,
父类实例保存在父类表中,子类实例由父类表和子类表共同存储
。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中。
在这种映射策略下,无须使用鉴别者列,但
需要为每个子类使用
key
元素映射共有主键
,
该主键必须与父类标识属性的列名相同
。但如果继承树的深度很深,可能查询一个子类实例时,需要跨越多个表,因为子类的数据一次保存在多个父类中。
子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中
代码示例: 未贴出的和(1)相同
Employee.hbm.xml 配置文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="cn.itcast.extends02.Employee" table="e_emp" >
<id name="id" type="integer">
<column name="id"/>
<generator class="increment"/>
</id>
<property name="name" type="string">
<column name="name"/>
</property>
<!--
使用joined-subclass映射子类
name="cn.itcast.extends02.HourEmployee":子类的类的完整路径
table="h_emp":子类对应的表
-->
<joined-subclass name="cn.itcast.extends02.HourEmployee" table="h_emp">
<!--表示h_emp 表中的主键,同时又是外键-->
<key column="hid"/>
<property name="rate" column="rate" type="double"/>
</joined-subclass>
<joined-subclass name="cn.itcast.extends02.SalaryEmployee" table="s_emp">
<key column="sid"/>
<property name="salary" column="salary" type="double"/>
</joined-subclass>
</class>
</hibernate-mapping>
App.java
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.junit.Test;
public class App {
private static SessionFactory sf=null;
static{
Configuration config=new Configuration();
config.configure("cn/itcast/extends02/hibernate.cfg.xml");
config.addClass(Employee.class);
sf=config.buildSessionFactory();
}
/*
* 知识点1: 保存员工信息
*/
@Test
public void saveStudentAndCoure(){
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
Employee e=new Employee();
e.setName("xxxx");
HourEmployee he=new HourEmployee();
he.setName("小昭");
he.setRate(10d);
SalaryEmployee se=new SalaryEmployee();
se.setName("赵敏");
se.setSalary(3000d);
session.save(e);
session.save(he);
session.save(se);
tx.commit();
session.close();
}
//知识点2: 查询钟点工信息
@Test
public void findHourEmployee(){
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
//可以使用子类
Query query=session.createQuery("from HourEmployee");
query.list();
tx.commit();
session.close();
}
//知识点5: 查询员工信息
@Test
public void findEmployee(){
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
//可以使用子类
Query query=session.createQuery("from Employee");
query.list();
tx.commit();
session.close();
}
//知识点6: 删除员工信息(不用使用级联) 删除2号员工
@Test
public void removeEmployee(){
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
Employee e2=(Employee)session.get(Employee.class, 2);
session.delete(e2);
tx.commit();
session.close();
}
//知识点7:查询唯一的员工,不是钟点工也不是正式员工
@Test
public void findUniqueEmployee(){
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
//sql SELECT * FROM e_emp e WHERE e.id NOT IN(SELECT hid FROM h_emp) AND e.id NOT IN(SELECT sid FROM s_emp)
Query query=session.createQuery("from Employee e where e.id not in(select h.id from HourEmployee h) and e.id not in(select s.id from SalaryEmployee s)");
query.list();
tx.commit();
session.close();
}
}