第一种
一个员工类它有两个子类,利用hibernate我们把这员工类及子类都映射到一张表里,员工表是普通员工,子类的
话是技术员工的类和销售员工 那么这三个类怎么映射到一张表里,我们又如何区分这员工的到底是哪一类员工呢
这时,我们一般在表中加入了一个识别的字段,比如说type 这个字段有三个值,默认值为0 表示的普通员工,1是
技术员工 2是销售员工
好,现在开始
设计主体员工实体类
package vo.util.bean;
/**
* 员工类
* @author Administrator
*
*/
public class Employee {
private int id;
private String name;
private Department derpartment;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Department getDerpartment() {
return derpartment;
}
public void setDerpartment(Department derpartment) {
this.derpartment = derpartment;
}
}
技术员工类 继承主体员工类
package vo.util.bean;
public class Skiller extends Employee {
private String skill;
public String getSkill() {
return skill;
}
public void setSkill(String skill) {
this.skill = skill;
}
}
销售员工类 继承主体员工类
package vo.util.bean;
public class Sales extends Employee {
private int sale;
public int getSale() {
return sale;
}
public void setSale(int sale) {
this.sale = sale;
}
}
主体实体映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="vo.util.bean">
<class name="Employee" discriminator-value="0">
<id name="id">
<generator class="native"/>
</id>
<discriminator column="type"/>
<property name="name"/>
<many-to-one name="derpartment" column="depaer_id" not-null="true"/>
<subclass name="Sales" discriminator-value="1">
<property name="sale"/>
</subclass>
<subclass name="Skiller" discriminator-value="2">
<property name="skill"/>
</subclass>
</class>
</hibernate-mapping>
分析 subclass 就是子类的意思 在这里的节点就是配置就是主实体的子类的配置
name 子实体名称 property 子实体的属性 discriminator-value识别字段值
discriminator节点 加入主表的识别字段 column="type"就是识别字段的列名是type
这个列默认的字段默认类型是string 可以加入 type="string" 就可以设计这个列的值的
类型
测试类
package vo.util.test;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.Transaction;
import vo.util.HibernateUtil;
import vo.util.bean.Department;
import vo.util.bean.Employee;
import vo.util.bean.Sales;
import vo.util.bean.Skiller;
public class OneToMany {
/**
* @param args
*/
public static void main(String[] args) {
add();
query(1);
}
static Department add(){
Session session = null;
Transaction tx = null;
try{
session =HibernateUtil.getSession();
tx = session.beginTransaction();
//…你的代码save,delete,update,get…
Department dpart=new Department();
dpart.setName("政企事业部");
Employee em1=new Employee();
em1.setName("员工李小仙");
em1.setDerpartment(dpart);
Employee em2=new Employee();
em2.setName("员工张小三");
em2.setDerpartment(dpart);
Skiller s=new Skiller();
s.setDerpartment(dpart);
s.setName("员工高明明");
s.setSkill("skill");
Sales sl=new Sales();
sl.setDerpartment(dpart);
sl.setName("小凤仙");
sl.setSale(2);
/**
Set<Employee> em=new HashSet<Employee>();
em.add(em1);
em.add(em2);
em.add(sl);
em.add(s);
dpart.setEms(em);
*/
session.save(dpart);
session.save(em1);
session.save(em2);
session.save(s);
session.save(sl);
tx.commit();
return dpart;
}finally{
if(session != null)session.close();
}
}
static Department query(int id){
Session session=null;
try{
session=HibernateUtil.getSession();
Department d=(Department)session.get(Department.class, id);
System.out.println(d.getName()+"--------->"+d.getEms().getClass().getName());
return d;
}finally{
if(session != null)session.close();
}
}
}
映射的表的值
1,"0","员工李小仙",1,NULL,NULL
2,"0","员工张小三",1,NULL,NULL
3,"2","员工高明明",1,NULL,"skill"
4,"1","小凤仙", 1, 2, NULL
发现表中的值有很多值为空值
现在我们来看表结构
CREATE TABLE `employee` (
`id` int(11) NOT NULL auto_increment,
`type` varchar(255) NOT NULL,
`name` varchar(255) default NULL,
`depaer_id` int(11) NOT NULL,
`sale` int(11) default NULL,
`skill` varchar(255) default NULL,
PRIMARY KEY (`id`),
KEY `FK4AFD4ACE59BDCD94` (`depaer_id`),
CONSTRAINT `FK4AFD4ACE59BDCD94` FOREIGN KEY (`depaer_id`) REFERENCES `department` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
但是这样是不是不合理呢?怎么修正它呢 ?
第二种方式
可以这样来,我们可以根据子类实体也新建一张表,比如技术员工,就新建一张技术员工表
同时新建的表如何跟主表employee连接呢?我们可以这样类设计,子表的id就是employee的id
这个字表的id不但是主键同时也是一个外键,引用的是主表的id
那现在我们来设计吧 joined-subclass节点的作用就出来了
主实体和子实体都不变
只需要修改员工的employee的映射文件便可
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="vo.util.bean">
<class name="Employee">
<id name="id">
<generator class="native"/>
</id>
<!-- <discriminator column="type"/>-->
<property name="name"/>
<many-to-one name="derpartment" column="depaer_id" not-null="true"/>
<!--
<subclass name="Sales" discriminator-value="1">
<property name="sale"/>
</subclass>
<subclass name="Skiller" discriminator-value="2">
<property name="skill"/>
</subclass>
-->
<joined-subclass name="Sales">
<key column="emp_id"/>
<property name="sale"/>
</joined-subclass>
<joined-subclass name="Skiller">
<key column="emp_id"/>
<property name="skill"/>
</joined-subclass>
</class>
</hibernate-mapping>
分析:joined-subclass 节点就是引入子实体类 key节点就是外键主键名称
property 就是子实体的属性
测试类不变
测试后输出的sql
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
打开连接成功!Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depaer_id) values (?, ?)
Hibernate: insert into Employee (name, depaer_id) values (?, ?)
Hibernate: insert into Employee (name, depaer_id) values (?, ?)
Hibernate: insert into Skiller (skill, emp_id) values (?, ?)
Hibernate: insert into Employee (name, depaer_id) values (?, ?)
Hibernate: insert into Sales (sale, emp_id) values (?, ?)
Hibernate: select department0_.id as id0_0_, department0_.name as name0_0_ from Department department0_ where department0_.id=?
Hibernate: select ems0_.depaer_id as depaer3_1_, ems0_.id as id1_, ems0_.id as id1_0_, ems0_.name as name1_0_, ems0_.depaer_id as depaer3_1_0_, ems0_1_.sale as sale2_0_, ems0_2_.skill as skill3_0_, case when ems0_1_.emp_id is not null then 1 when ems0_2_.emp_id is not null then 2 when ems0_.id is not null then 0 end as clazz_0_ from Employee ems0_ left outer join Sales ems0_1_ on ems0_.id=ems0_1_.emp_id left outer join Skiller ems0_2_ on ems0_.id=ems0_2_.emp_id where ems0_.depaer_id=?
政企事业部--------->[vo.util.bean.Employee@fcfa52, vo.util.bean.Sales@1fc6e42, vo.util.bean.Skiller@18b81e3, vo.util.bean.Employee@961dff]
现在来看表结构
CREATE TABLE `employee` (
`id` int(11) NOT NULL auto_increment,
`name` varchar(255) default NULL,
`depaer_id` int(11) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK4AFD4ACE59BDCD94` (`depaer_id`),
CONSTRAINT `FK4AFD4ACE59BDCD94` FOREIGN KEY (`depaer_id`) REFERENCES `department` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
子表
CREATE TABLE `sales` (
`emp_id` int(11) NOT NULL,
`sale` int(11) default NULL,
PRIMARY KEY (`emp_id`),
KEY `FK4BF58ECF47ACFA7` (`emp_id`),
CONSTRAINT `FK4BF58ECF47ACFA7` FOREIGN KEY (`emp_id`) REFERENCES `employee` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE `skiller` (
`emp_id` int(11) NOT NULL,
`skill` varchar(255) default NULL,
PRIMARY KEY (`emp_id`),
KEY `FKE3361E9EF47ACFA7` (`emp_id`),
CONSTRAINT `FKE3361E9EF47ACFA7` FOREIGN KEY (`emp_id`) REFERENCES `employee` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
第三种方式
为了效率的提高 我们可以结合这两种的映射配置映射文件,可以去试下吧
第四种方式 员工是一张完整的表 技术员工 销售员工都是一张完整的信息表
主实体及子实体都不变
修改Employee的映射文件
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping
package="vo.util.bean">
<class name="Employee" discriminator-value="0">
<id name="id">
<generator class="native"/>
</id>
<!--
<discriminator column="type"/>
-->
<property name="name"/>
<many-to-one name="derpartment" column="depaer_id" not-null="true"/>
<!--
<subclass name="Sales" discriminator-value="1">
<property name="sale"/>
</subclass>
<subclass name="Skiller" discriminator-value="2">
<property name="skill"/>
</subclass>
-->
<union-subclass name="Sales" table="tables">
<property name="sale"/>
</union-subclass>
<union-subclass name="Skiller" table="skill">
<property name="skill"/>
</union-subclass>
</class>
</hibernate-mapping>
union-subclass节点配置 name="Sales" 就是对应的实体类 table 给子实体指定的表
property 节点是属性名 就是对应子实体的属性
测试类不变
运行测试
log4j:WARN No appenders could be found for logger (org.hibernate.cfg.Environment).
log4j:WARN Please initialize the log4j system properly.
Exception in thread "main" java.lang.ExceptionInInitializerError
at vo.util.test.OneToMany.add(OneToMany.java:29)
at vo.util.test.OneToMany.main(OneToMany.java:22)
Caused by: org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: vo.util.bean.Employee
at org.hibernate.persister.entity.UnionSubclassEntityPersister.<init>(UnionSubclassEntityPersister.java:67)
at org.hibernate.persister.PersisterFactory.createClassPersister(PersisterFactory.java:61)
at org.hibernate.impl.SessionFactoryImpl.<init>(SessionFactoryImpl.java:226)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1294)
at vo.util.HibernateUtil.<clinit>(HibernateUtil.java:23)
... 2 more
发现报实体异常,意思说说主键的生成器 identity 问题 这是什么原因造成的呢?
主键生成错误 看配置文件 <generator class="native"/> 这种主键生成是自增长得,那么这个三张表会产生
主键值是一样的 主键值代表的是一条记录
所以可以改成hilo
end 完毕!