一、第一种设计:员工类、销售人员类、技术人员类三个类数据(属性)放在一张表中
为了区分各类,添加一个type(类型)字段,在hibernate中映射文件里有个叫鉴别器与之对应。
设置鉴别器和discriminator-value的值,以表示不同类型
SQL> desc employee;
Name Type Nullable Default Comments
--------- ------------- -------- ------- --------
ID NUMBER(10)
TYPE NUMBER(10)
NAME VARCHAR2(255)
DEPART_ID NUMBER(10)
SKILL VARCHAR2(255) Y
SELL VARCHAR2(255) Y
查询:
select
emps0_.depart_id as depart4_0_1_,
emps0_.id as id1_1_1_,
emps0_.id as id1_1_0_,
emps0_.name as name3_1_0_,
emps0_.depart_id as depart4_1_0_,
emps0_.skill as skill5_1_0_,
emps0_.sell as sell6_1_0_,
emps0_.type as type2_1_0_
from
Employee emps0_
where
emps0_.depart_id=?
<?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 package="cn.itcast.domain">
<class name="Employee" discriminator-value="0">
<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
<id name="id" column="id">
<!-- 指定主键生成方式。
native根据方言判定生成主键的方式
-->
<generator class="native"/>
</id>
<!-- 鉴别器 默认是string的-->
<discriminator column="type" type="int"/>
<property name="name" column="name" unique="true" not-null="true"/><!--标示name唯一性,非空的限制 -->
<!-- private Department depart是一个复杂的属性,所以不能用 property映射-->
<!--Employee类中Department的对象名 -->
<many-to-one name="depart" column="depart_id" not-null="true" ></many-to-one>
<!-- 实现继承关系,子类 -->
<subclass name="Skiller" discriminator-value="1">
<!-- 子类特有属性 -->
<property name="skill"/>
</subclass>
<subclass name="Sales" discriminator-value="2">
<!-- 子类特有属性 -->
<property name="sell"/>
</subclass>
</class>
</hibernate-mapping>
hibernate是支持多态的查询,查询子类时会加type字段限制查询。
优点:因为是一张表所以sql比较少,效率高。
缺点:1.对于单个类来说,是有些字段是多余的,而且每次添加子类,还得修改表结构添加字段
2.字段不能定义成非空约束
3.关系映射不清晰
二、第二种方式:
将共有字段放在一张表(父类属性),将按照子类特有的字段单独见表,添加于共有字段表(父类表)关联的外键
这样以后再有新的子类继承,父类的表不用修改,子类建表后添加于父类表关联的外键。
此时不需要鉴别器字段
添加事件:数据各插入各的表中。
查询是如果是单条说明是,支持多态查询,到时候两表关联。
查询主表时,有多少个子表都会查询出来。
查询时多表关联,效率低。
数据也有没有null的字段了
缺点:效率会低很多。
有点:数据模型和关系模型比较清晰
-- Create table
create table SKILLER
(
EMP_ID NUMBER(10) not null,
SKILL VARCHAR2(255)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table SKILLER
add primary key (EMP_ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table SKILLER
add constraint FK_EDA25E87FE3E49589E6A0DB53FC foreign key (EMP_ID)
references EMPLOYEE (ID);
-- Create table
create table SALES
(
EMP_ID NUMBER(10) not null,
SELL VARCHAR2(255)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table SALES
add primary key (EMP_ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table SALES
add constraint FK_D317846FD46A485F9712462F3F3 foreign key (EMP_ID)
references EMPLOYEE (ID);
查询时的语句:
select
emps0_.depart_id as depart3_0_1_,
emps0_.id as id1_1_1_,
emps0_.id as id1_1_0_,
emps0_.name as name2_1_0_,
emps0_.depart_id as depart3_1_0_,
emps0_1_.skill as skill2_7_0_,
emps0_2_.sell as sell2_6_0_,
decode(emps0_.id,
emps0_1_.emp_id,
1,
emps0_2_.emp_id,
2,
0) as clazz_0_
from
Employee emps0_,
skiller emps0_1_,
sales emps0_2_
where
emps0_.id=emps0_1_.emp_id(+)
and emps0_.id=emps0_2_.emp_id(+)
and emps0_.depart_id=?
效率比较低啊!
<?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 package="cn.itcast.domain">
<class name="Employee">
<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
<id name="id" column="id">
<!-- 指定主键生成方式。
native根据方言判定生成主键的方式
-->
<generator class="native"/>
</id>
<property name="name" column="name" unique="true" not-null="true"/><!--标示name唯一性,非空的限制 -->
<!-- private Department depart是一个复杂的属性,所以不能用 property映射-->
<!--Employee类中Department的对象名 -->
<many-to-one name="depart" column="depart_id" not-null="true" ></many-to-one>
<joined-subclass name="Skiller" table="skiller">
<!-- 外键属性 -->
<key column="emp_id"/>
<property name="skill"/>
</joined-subclass>
<joined-subclass name="Sales" table="sales">
<!-- 外键属性 -->
<key column="emp_id"/>
<property name="sell"/>
</joined-subclass>
</class>
</hibernate-mapping>
三、一二混合使用
子类字段多的单独成表,字段少的子类融合与父类表中
如果鉴别器的值是缺省的,表示同类的全名称
表结构:
-- Create table
create table SALES
(
EMP_ID NUMBER(10) not null,
SELL VARCHAR2(255)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table SALES
add primary key (EMP_ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table SALES
add constraint FK_92D3A784698A46C39125AB209DC foreign key (EMP_ID)
references EMPLOYEE (ID);
查询:
Hibernate:
select
department0_.id as id1_0_0_,
department0_.name as name2_0_0_
from
Department department0_
where
department0_.id=?
Hibernate:
select
emps0_.depart_id as depart4_0_1_,
emps0_.id as id1_1_1_,
emps0_.id as id1_1_0_,
emps0_.name as name3_1_0_,
emps0_.depart_id as depart4_1_0_,
emps0_.skill as skill5_1_0_,
emps0_1_.sell as sell2_6_0_,
emps0_.type as type2_1_0_
from
Employee emps0_,
sales emps0_1_
where
emps0_.id=emps0_1_.emp_id(+)
and emps0_.depart_id=?、
查询语句进行了简化,效率得到了一定的提升。
<?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 package="cn.itcast.domain">
<class name="Employee" discriminator-value="0">
<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
<id name="id" column="id">
<!-- 指定主键生成方式。
native根据方言判定生成主键的方式
-->
<generator class="native"/>
</id>
<discriminator column="type" type="int"/>
<property name="name" column="name" unique="true" not-null="true"/><!--标示name唯一性,非空的限制 -->
<!-- private Department depart是一个复杂的属性,所以不能用 property映射-->
<!--Employee类中Department的对象名 -->
<many-to-one name="depart" column="depart_id" not-null="true" ></many-to-one>
<subclass name="Skiller" discriminator-value="1">
<!-- 子类特有属性 -->
<property name="skill"/>
</subclass>
<subclass name="Sales" discriminator-value="2">
<join table="sales">
<key column="emp_id"/>
<property name="sell"/>
</join>
</subclass>
</class>
</hibernate-mapping>
四、对于每个具体的类映射一张独立的表
这样查询的效率就搞了许多
每张表信息都是完整的,所以不需要关联了。
要求三张表id不能有重复的
-- Create table
create table SKILLER
(
ID NUMBER(10) not null,
NAME VARCHAR2(255) not null,
DEPART_ID NUMBER(10) not null,
SKILL VARCHAR2(255)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table SKILLER
add primary key (ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table SKILLER
add constraint UK_8D22F1643A4F458ABFE17C98CBA unique (NAME)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
-- Create table
create table SALES
(
ID NUMBER(10) not null,
NAME VARCHAR2(255) not null,
DEPART_ID NUMBER(10) not null,
SELL VARCHAR2(255)
)
tablespace USERS
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 64
minextents 1
maxextents unlimited
);
-- Create/Recreate primary, unique and foreign key constraints
alter table SALES
add primary key (ID)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
alter table SALES
add constraint UK_F741420610874DCE9B5FAD28FF7 unique (NAME)
using index
tablespace USERS
pctfree 10
initrans 2
maxtrans 255
storage
(
initial 64K
minextents 1
maxextents unlimited
);
<?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 package="cn.itcast.domain">
<class name="Employee" >
<!-- 对象标示符,类型可以不写,hibernate自己识别 -->
<id name="id" column="id">
<!-- 指定主键生成方式。
native根据方言判定生成主键的方式
-->
<generator class="native"/>
</id>
<property name="name" column="name" unique="true" not-null="true"/><!--标示name唯一性,非空的限制 -->
<!-- private Department depart是一个复杂的属性,所以不能用 property映射-->
<!--Employee类中Department的对象名 -->
<many-to-one name="depart" column="depart_id" not-null="true" ></many-to-one>
<union-subclass name="Skiller" table="skiller">
<property name="skill"></property>
</union-subclass>
<union-subclass name="Sales" table="sales">
<property name="sell"></property>
</union-subclass>
</class>
</hibernate-mapping>
查询表:
select
emps0_.depart_id as depart3_0_1_,
emps0_.id as id1_1_1_,
emps0_.id as id1_1_0_,
emps0_.name as name2_1_0_,
emps0_.depart_id as depart3_1_0_,
emps0_.skill as skill1_7_0_,
emps0_.sell as sell1_6_0_,
emps0_.clazz_ as clazz_0_
from
( select
id,
name,
depart_id,
to_char(null) as skill,
to_char(null) as sell,
0 as clazz_
from
Employee
union
all select
id,
name,
depart_id,
skill,
to_char(null) as sell,
1 as clazz_
from
skiller
union
all select
id,
name,
depart_id,
to_char(null) as skill,
sell,
2 as clazz_
from
sales
) emps0_
where
emps0_.depart_id=?
就是和单表的是一样的。
在class标签上添加abstract="true"表示继承抽象类,则抽象类不会建表
继承总结:表的个数不要超过类的个数
测试类:
package cn.itcast.RelationalMapping;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Hibernate;
import org.hibernate.Session;
import org.hibernate.Transaction;
import cn.itcast.dao.HibernateUtil;
import cn.itcast.domain.Department;
import cn.itcast.domain.Employee;
import cn.itcast.domain.Sales;
import cn.itcast.domain.Skiller;
/**
* 一对多测试类
* @author Mars
*
*/
public class One2many {
/**
* @param args
*/
public static void main(String[] args) {
//Department dept = add();
Department dept = add3();
System.out.println("------------------------------------");
queryDepart(dept.getId());
}
/**
* 一对多查询方法
* @param empId
* @return
*/
static Department queryDepart(int deptId){
Session s = null;
Transaction tx =null;
try {
s=HibernateUtil.getSession();
tx=s.beginTransaction();
Department depart = (Department)s.get(Department.class, deptId);
// 分两步:1,根据departid查询部门的相关数据
// 2.根据departid查询相应的employee相关数据
// System.out.println("emp size:"+depart.getEmps().size());
/**
* 为了显示更直观下,我没覆盖Employee类的toString()
*/
System.out.println("emp:"+depart.getEmps());
//涉及懒加载先这么写吧
Hibernate.initialize(depart.getEmps());
tx.commit();
return depart;
} finally{
if(s!=null){
s.close();
}
}
}
/**
* 一对多添加方法
* 告诉用户所从属的部门
* @return
*/
static Department add(){
Session s = null;
Transaction tx =null;
try {
Department depart = new Department();
depart.setName("depart name");
//告诉用户所从属的部门
Employee emp1 = new Employee();
emp1.setDepart(depart);//对象模型,建立两个对象的关联
emp1.setName("emp name1");
Employee emp2 = new Employee();
emp2.setDepart(depart);//对象模型,建立两个对象的关联
emp2.setName("emp name2");
s=HibernateUtil.getSession();
tx=s.beginTransaction();
s.save(depart);
s.save(emp1);
s.save(emp2);
tx.commit();
return depart;
} finally{
if(s!=null){
s.close();
}
}
}
/**
* 一对多添加方法
* 告诉用户所从属的部门及告诉部门所从属的员工
* @return
*/
static Department add2(){
Session s = null;
Transaction tx =null;
try {
Department depart = new Department();
depart.setName("depart name");
//告诉用户所从属的部门
Employee emp1 = new Employee();
emp1.setDepart(depart);//对象模型,建立两个对象的关联
emp1.setName("emp name1");
Employee emp2 = new Employee();
emp2.setDepart(depart);//对象模型,建立两个对象的关联
emp2.setName("emp name2");
/**
* set时
*/
Set<Employee>emps = new HashSet<Employee>();
emps.add(emp1);
emps.add(emp2);
depart.setEmps(emps);
/* //告诉部门所从属的员工
//list集合时
List<Employee>emps = new ArrayList<Employee>();
emps.add(emp1);
emps.add(emp2);
depart.setEmps(emps);*/
/**
* Map集合时
*/
// Map<String,Employee>emps = new HashMap<String,Employee>();
// emps.put(emp1.getName(), emp1);
// emps.put(emp2.getName(), emp2);
// depart.setEmps(emps);
/**
* 数组
*/
/* Employee[] emps = {emp1,emp2};
depart.setEmps(emps);*/
s=HibernateUtil.getSession();
tx=s.beginTransaction();
s.save(depart);
s.save(emp1);
s.save(emp2);
tx.commit();
//做个试验
// HashSet hs =(HashSet)depart.getEmps();
return depart;
} finally{
if(s!=null){
s.close();
}
}
}
/**
* 继承关系
* @return
*/
static Department add3(){
Session s = null;
Transaction tx =null;
try {
Department depart = new Department();
depart.setName("depart name");
//告诉用户所从属的部门
Employee emp1 = new Employee();
emp1.setDepart(depart);//对象模型,建立两个对象的关联
emp1.setName("emp name1");
Skiller emp2 = new Skiller();
emp2.setDepart(depart);//对象模型,建立两个对象的关联
emp2.setName("emp name2");
emp2.setSkill("skill");
Sales emp3 = new Sales();
emp3.setDepart(depart);//对象模型,建立两个对象的关联
emp3.setName("emp name3");
emp3.setSell("sell");
s=HibernateUtil.getSession();
tx=s.beginTransaction();
s.save(depart);
s.save(emp1);
s.save(emp2);
s.save(emp3);
tx.commit();
return depart;
} finally{
if(s!=null){
s.close();
}
}
}
}
子类:
package cn.itcast.domain;
/**
* 技术工种
* @author Mars
*
*/
public class Skiller extends Employee {
private String skill;//技能
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
package cn.itcast.domain;
/**
* 销售人员
* @author Mars
*
*/
public class Sales extends Employee {
private String sell;
public String getSell() {
return sell;
}
public void setSell(String sell) {
this.sell = sell;
}
}