学习笔记14--继承关系_整个继承树映射

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





 

你可能感兴趣的:(学习笔记14--继承关系_整个继承树映射)