第十二章 继承关系的映射
继承模型
在企业中经常会有员工的分类
我们在Java对象模型中可以使用继承的关系来实现,如下图:
?一张表映射
数据库中表的结构如下:
ID姓名地址生日开发人员技能销售人员技能员工类型
我们可以约定一种员工类型的规则,比如0普通员工,1开发人员,2销售人员
接下来,我们看一下Model层的实现和映射文件的编写:
Employee:
public class Employee {
protected String id;
protected String name;
protected String address;
protected Date birthday;
public Employee() {
super();
}
public Employee(String name, String address, Date birthday) {
super();
this.name = name;
this.address = address;
this.birthday = birthday;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
Programmer:
public class Programmer extends Employee {
private String skill;
public Programmer(String name, String address, Date birthday, String skill) {
super(name, address, birthday);
this.skill = skill;
}
public Programmer() {
super();
}
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
Seller:
public class Seller extends Employee {
private String sell;
public Seller() {
super();
}
public Seller(String name, String address, Date birthday, String sell) {
super(name, address, birthday);
this.sell = sell;
}
public String getSell() {
return sell;
}
public void setSell(String sell) {
this.sell = sell;
}
}
映射文件:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees"
discriminator-value="0">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator />
</id>
<discriminator column="type" type="int" />
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday"
length="10" />
<subclass name="chapter5.model.Programmer" discriminator-value="1">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</subclass>
<subclass name="chapter5.model.Seller" discriminator-value="2">
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</subclass>
</class>
</hibernate-mapping>
<discriminator column="type" type="int" />
鉴别器是给Hibernate来区分类型用的.就像listIndex是给list标签来记住元素顺序的作用是一样的,我们使用时不需要去理会这个字段,我们还是按我们平常的使用方式即可.
Dao层:
public class EmployeeDao {
public void create(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.save(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public void delete(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.delete(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public void update(Employee employee) throws Exception {
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
session.update(employee);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
}
public Employee findById(Serializable id) throws Exception {
Session session = null;
Employee employee = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSession();
transaction = session.getTransaction();
transaction.begin();
employee = (Employee) session.get(Employee.class, id);
transaction.commit();
} catch (Exception e) {
transaction.rollback();
throw e;
}
return employee;
}
}
Test:
public class Test {
public static void main(String[] args) throws Exception {
EmployeeDao employeeDao = new EmployeeDao();
Employee employee = new Employee("张三", "武汉", new Date());
Programmer programmer = new Programmer("李四", "咸宁", new Date(),
"Java,sql,JS");
Seller seller = new Seller("李四", "襄樊", new Date(), "一流的销售技能");
employeeDao.create(employee);
employeeDao.create(programmer);
employeeDao.create(seller);
}
}
查找员工时应该注意要转型:
public class Test {
public static void main(String[] args) throws Exception {
EmployeeDao employeeDao = new EmployeeDao();
Employee employee = employeeDao
.findById("40285c8127d5f31b0127d5f31d4e0001");
System.out.println(employee.getName());
Programmer programmer = (Programmer) employeeDao
.findById("40285c8127d5f31b0127d5f31dbb0002");
System.out.println(programmer.getName() + ":" + programmer.getSkill());
Seller seller = (Seller) employeeDao
.findById("40285c8127d5f31b0127d5f31dcb0003");
System.out.println(seller.getName() + ":" + seller.getSell());
}
}
这种方法有个僻端:
可以看到数据库中,有很多空白的字段出现.
?解决方案:每个类映射到一张表
员工表:
ID姓名地址生日
开发人员表
ID(主键,外键)掌握的开发技能
销售人员表
ID(主键,外键)掌握的销售技能
表之间的关系
类模型不动,主要改动配置文件即可.
Dao层也不动,Test也不动
配置文件改动如下:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator />
</id>
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<joined-subclass name="chapter5.model.Programmer"
table="programmer">
<key column="id" />
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</joined-subclass>
<joined-subclass name="chapter5.model.Seller" table="seller">
<key column="id" />
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</joined-subclass>
</class>
</hibernate-mapping>
<key column="id" /> id在这里即是主键又是外键, 和一对一关系差不多, 指定的是子表的ID
再运行一下Test文件的增加代码,可以看到生成了三张表.
运行一下查询代码,可以看到,查询是多表联合查询,在查询效率上比一张表要复杂一些,但是在表结构上却合理的多.
?第三种解决方案
鉴别器与子表接合方案
比如开发人员表中只有一个字段,销售人员表中有多个字段,那么为开发人员单独加一张表有点浪费,可以将开发人员表与普通员工表二合一,只需要单独为销售人员增加一张表即可.
只需要改动配置文件即可:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees"
discriminator-value="0">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator />
</id>
<discriminator column="type" type="int" />
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<subclass name="chapter5.model.Programmer"
discriminator-value="1">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</subclass>
<subclass name="chapter5.model.Seller" discriminator-value="2">
<join table="seller">
<key column="id" />
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</join>
</subclass>
</class>
</hibernate-mapping>
?第四种解决方案:
每个类映射一张表
适用于公共字段较少的情况.
映射文件如下:
<hibernate-mapping>
<class name="chapter5.model.Employee" table="employees">
<id name="id" type="java.lang.String">
<column name="id" length="32" />
<generator />
</id>
<property name="name" type="java.lang.String" column="name"
length="20" />
<property name="address" type="java.lang.String" column="address"
length="20" />
<property name="birthday" type="java.util.Date" column="birthday" />
<union-subclass name="chapter5.model.Programmer" table="programmer">
<property name="skill" type="java.lang.String" column="skill"
length="100" />
</union-subclass>
<union-subclass name="chapter5.model.Seller" table="seller">
<property name="sell" type="java.lang.String" column="sell"
length="100" />
</union-subclass>
</class>
</hibernate-mapping>
以上就是解决继承的四种方案