1.采用 subclass 元素的继承映射
* 每个具体类一张表(table per concrete class) 将域模型中的每一个实体对象映射到一个独立的表中,也就是说不用在关系数据模型中考虑域模型中的继承关系和多态。
* 父类和子类使用同一张表(有一个区分类型的字段)
* 采用 subclass 的继承映射可以实现对于继承关系中父类和子类使用同一张表
* 因为父类和子类的实例全部保存在同一个表中,因此需要在该表内增加一列,使用该列来区分每行记录到底是哪个类的实例----这个列被称为辨别者列(discriminator).
/**
* 钟点工
*/
public class HourEmployee extends Employee{
/**
* 正式员工
*/
public class SalaryEmployee extends Employee {
hibernate配置文件
<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>
* 辨别者列,用于区分员工的种类,该配置必须放置在id的后面
* 普通员工的辨别者列值为ee,小时工辨别者列的值为he,正式员工的辨别者列的值为se
* 在这种映射策略下,使用 subclass 来映射子类,使用 class 或 subclass 的 discriminator-value 属性指定辨别者列的值
* 所有子类定义的字段都不能有非空约束。如果为那些字段添加非空约束,那么父类的实例在那些列其实并没有值,这将引起数据库完整性冲突,导致父类的实例无法保 存到数据库中
SalaryEmployee se=new SalaryEmployee();
se.setName("赵敏");
se.setSalary(3000d);
* double类型的值要加个d,默认数字都是int类型
1.1查询钟点工信息
@Test
public void findHourEmployee(){
Session session=sf.openSession();
Transaction tx=session.beginTransaction();
//可以使用子类
Query query=session.createQuery("from HourEmployee");
query.list();
tx.commit();
session.close();
}
查询语句 Hibernate: select houremploy0_.id as id0_, houremploy0_.name as name0_, houremploy0_.rate as rate0_ from employee houremploy0_ where houremploy0_.etype='he'
* 如果查询所有员工,hql语句为 from Employee 多态查询
2.采用 joined-subclass 元素的继承映射
* 采用 joined-subclass 元素的继承映射可以实现每个子类一张表
* 采用这种映射策略时,父类实例保存在父类表中,子类实例由父类表和子类表共同存储。因为子类实例也是一个特殊的父类实例,因此必然也包含了父类实例的属性。 于是将子类和父类共有的属性保存在父类表中,子类增加的属性,则保存在子类表中
<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>
* 子类增加的属性可以添加非空约束。因为子类的属性和父类的属性没有保存在同一个表中
* 在这种映射策略下,无须使用鉴别者列,但需要为每个子类使用 key 元素映射共有主键,该主键必须与父类标识属性的列名相同。
2.1.删除员工信息
@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();
}
* 删除员工信息,不用使用级联
2.2.查询唯一的员工,不是钟点工也不是正式员工
@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();
}
3.项目改造
<!-- 加载映射文件-->
<mapping resource="cn/itcast/add/Customer.hbm.xml"/>
<mapping resource="cn/itcast/add/Order.hbm.xml"/>
* 在Hibernate配置文件加载映射文件
Customer.hbm.xml
<class name="cn.itcast.add.Customer" table="customers" entity-name="customersk">
<id name="id" type="integer">
<column name="id"/>
<generator class="increment"/>
</id>
<property name="name" type="string">
<column name="name"/>
</property>
<set name="orderes" table="orders" inverse="true">
<key>
<column name="customer_id"/>
</key>
<one-to-many entity-name="ordersk"/>
</set>
</class>
Order.hbm.xml
<class name="cn.itcast.add.Order" table="orders" entity-name="ordersk">
<id name="id" type="integer">
<column name="id"/>
<generator class="increment"/>
</id>
<property name="orderNumber" type="string">
<column name="orderNumber"/>
</property>
<property name="price" type="double">
<column name="price"/>
</property>
<many-to-one name="customer" entity-name="customersk">
<column name="customer_id"/>
</many-to-one>
</class>
* entity-name:表示实体的名称 相当于起了一个别名
3.1.项目改造(保存save)
session.save("customersk",customer);
3.2.项目改在(修改
)
@Test
public void updateCustomer(){
CustomerDao customerDao=new CustomerDao();
Customer customer=new Customer();
customer.setId(1);
customer.setName("西门公子");
customerDao.updateCustomer(customer);
}
* 这种方式的修改的是新建一个对象,再使用update方法,临时对象没有在一级缓存里面,每次都会有update语句,不管属性有没有变
3.3.项目改造(查询list)
public List<Customer> findCustomers() {
Session session=null;
Transaction tx=null;
List<Customer> list=null;
try {
session=HibernateUtil.getSession();
if(session!=null){
tx=HibernateUtil.beginTransaction(session);
Query query=session.createQuery("from customersk");
list=query.list();
HibernateUtil.commitTransaction(tx);
}
} catch (HibernateException e) {
e.printStackTrace();
//事务回滚
HibernateUtil.rollbackTransaction(tx);
}finally{
HibernateUtil.closeSession(session);
}
return list;
}
* hql语句为from customersk customersk别名