首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 软件管理 > 软件架构设计 >

hibernate 沿袭映射

2012-10-23 
hibernate 继承映射在域模型中,类与类之间除了关联关系和聚集关系,还可以存在继承关系,在下图所示的域模型

hibernate 继承映射

在域模型中,类与类之间除了关联关系和聚集关系,还可以存在继承关系,在下图所示的域模型中,Deparment类和Employee类之间为一对多的双向关联关系,Employee类有两个子类:Skiller类和Sales类。由于Java只允许一个类最多有一个直接的父类,因此Employee类、 Skiller类和Sales类构成了一棵继承关系树。
hibernate 沿袭映射
?在面向对象的范畴中,还存在多态的概念,多态建立在继承关系的基础上。简单地理解,多态是指当一个Java应用变量被声明为Employee类时,这个变量实际上既可以引用Employee类自己的实例,Skiller类的实例,也可以引用Sales类的实例。Department类的getEmps()方法通过HibernateAPI从数据库中检索出所有Employee对象。getEmps()方法返回的集合既可以包含Employee类自己的实例,Skiller类的实例,也可以引用Sales类的实例。,这种查询被称为多态查询。数据库表之间并不存在继承关系,那么如何把域模型的继承关系映射到关系数据模型中呢?hibernate有以下三种映射方式:

继承关系树的根类对应一个表:对关系数据模型进行非常规设计,在数据库表中加入额外的区分子类型的字段。通过这种方式,可以使关系数据模型支持继承关系和多态。

继承关系树的每个类对应一个表(子类与父类通过外键关联):在关系数据模型中用外键参照关系来表示继承关系。

继承关系树的每个具体类对应一个表:关系数据模型完全不支持域模型中的继承关系和多态。

1.继承关系树的根类对应一个表employee(整个继承树一张表):

employee的表结构如下所示:

mysql> desc employee;
+------------+--------------+------+-----+---------+----------------+
| Field????? | Type???????? | Null | Key | Default | Extra????????? |
+------------+--------------+------+-----+---------+----------------+
| id???????? | int(11)????? | NO?? | PRI | NULL??? | auto_increment |
| type?????? | int(11)????? | NO?? |???? | NULL??? |??????????????? |
| name?????? | varchar(255) | YES? | UNI | NULL??? |??????????????? |
| depart_id? | int(11)????? | YES? | MUL | NULL??? |??????????????? |
| skill????? | varchar(255) | YES? |???? | NULL??? |??????????????? |
| saleAmount | int(11)????? | YES? |???? | NULL??? |??????????????? |
+------------+--------------+------+-----+---------+----------------+

实体类Department和Employee请参看我前面的文章,Skiller和Sales分别如下所示:

?

?测试类如下:


?修改Employee.hbm.xml映射文件如下所示:

?测试类不变,只是将测试代码中注释为1的语句改成:


?Employee.hbm.xml映射文件如下所示:

?此时测试类不变,只是将测试代码中注释为1的语句改成:

Caused by: com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: Unknown column 'type' in 'field list'

这是因为我在hibernate.cfg.xml配置文件中配置了此项:

不配置discriminator-value="1",则会抛出如下异常:

java.lang.ExceptionInInitializerError

Caused by: org.hibernate.MappingException: Could not format discriminator value to SQL string

因为如果discriminator-value没有显式的给定值的话,则与name属性的值保持一致,即为Skiller ,所以会抛出如上异常!

?

4.继承关系树的每个具体类对应一个表(union-subclass)

表结构如下所示:


hibernate 沿袭映射

Employee.hbm.xml映射文件如下:

?此时主键增长不能再是:

因为如果使用native的话三张表会产生相同的id值,这样当根据id查询Employee时就会出错了。所以如果你配置成native时会抛出如下异常(因为Employee实体类中id对应 的是int了,所以在此使用hilo(高低位)主键生成方式):

org.hibernate.MappingException: Cannot use identity column key generation with <union-subclass> mapping for: com.reiyen.hibernate.domain.Skiller

?

运行测试程序后,此时控制台打印信息如下所示:

Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (name, depart_id, id) values (?, ?, ?)
Hibernate: insert into skiller (name, depart_id, skill, id) values (?, ?, ?, ?)
Hibernate: insert into sales (name, depart_id, sale_amount, id) values (?, ?, ?, ?)
Hibernate: select employee0_.id as id1_0_, employee0_.name as name1_0_, employee0_.depart_id as depart3_1_0_, employee0_.skill as skill2_0_, employee0_.sale_amount as sale1_3_0_, employee0_.clazz_ as clazz_0_ from ( select id, null as sale_amount, depart_id, null as skill, name, 0 as clazz_ from Employee union select id, null as sale_amount, depart_id, skill, name, 1 as clazz_ from skiller union select id, sale_amount, depart_id, null as skill, name, 2 as clazz_ from sales ) employee0_ where employee0_.id=?
class com.reiyen.hibernate.domain.Skiller

执行查询时,首先使用子查询,在子查询中使用union将三张表的结果全成一张表,然后再在合成的结果集中进行查询。

如果Employee是一个抽象类,你不想在数据表中对应相应的数据表,则可以设置abstract="true".如下所示:

? 此外,如果继承关系中有接口,可以把它当作抽象类对待。

三种映射方式的比较和选择
为了方便说明为三种方式按顺序标号为[1]整个继承树一张表;[2]每子类对应一个表(joined-subclass);[4]每个具体类对应一个表(union-subclass)。
1、复杂度:

??? [1]简单;
??? [2]表较多且之间有外键约束;

??? [4]包含重复字段;
2、查询性能:

??? [1]效率高;
??? [2]需要表内连接或左外连接;

??? [4]若查询父类需查所有子类表;
3、可维护性:

??? [1]只需修改一个表;
??? [2]若某个类属性变化只修改这个类对应的表;

??? [4]若父类属性变化需要修改所有子类对应的表;
综上,选择时,可以参考以下原则:
1、子类属性不是非常多时,优先考虑[1],因为其性能最佳。
2、子类属性非常多,且对性能要求不是很严格时,优先考虑[2]

1 楼 lionkingzw 2010-05-07   讲得蛮好的。学习了。

热点排行