一、第一种设计:员工类、销售人员类、技术人员类三个类数据(属性)放在一张表中
为了区分各类,添加一个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; } }