hibernate——继承关系以及三个subclass标签的区别

42 篇文章 0 订阅

Java类中有继承关系,相应的在hibernate中,也有继承关系,子类反应到数据库中,就有多种实现形式了,子类和父类可以映射到同一张表中,子类也可以单独映射成一张表,但是用不同的标签实现,子类表和父类表的关系也不同。在映射文件中,有三个标签可以实现继承关系,分别是:subclass、joined-subclass、union-subclass,先陈述一下这三个标签的区别:

subclass标签就是为子类嵌入父类的表中而设计的,而且要指定鉴别器,即用subclass一定要有判断类型的一个列,鉴别器指定记录属于哪个类型。但是subclass也提供了为子类设置单独的表的功能,即join标签。但是不管是内嵌表还是外部表,都得指定鉴别器。

joined-subclass标签,提供的功能是只能为子类设定外部表,而且没有鉴别器,即子类一张表,父类一张表,子类以父类的主键为外键。父类对应的表中,没有判断类型的列。

注意:这两个标签不能混用,若是只想要内嵌表,或者是既想要有内嵌表,又想要外部表,又或者是只想要外部表,那么只能使用subclass标签,需要注意的是,不论哪种方式,都要指定鉴别器,即父类对应的表中,一定有一个判断类型的列;而若是只想要外部表,又不想在父类对应的表中,要那个判断类型的列,那么只能使用join-subclass

union-subclass是将父类中的属性,添加到子类对应的表中去了。包括父类中的外键。union-class和前两个的区别就在于外键的不同,前两个标签,如果子类有单独对应的表的话,这个表的外键是其父类中的主键,而使用union-class,子类对应的表中的外键则和父类的外键是一样的,因为子类把父类继承的属性,也加到了自己的表当中。这样子类和父类的地位就相当了。不过这不是一种好的理解方式。如果是这样的话,那么就可以把父类设为抽象的类,并且在映射文件中,把父类设置为abstract="true",那么就不会再数据库中生成父类对应的表了,父类就只起到一个抽象的作用了。

下面列举员工和部门的例子说明,假设员工类还有两个子类:一个是技术人员,一个是销售人员:

[java]  view plain  copy
  1. public class Employee {  
  2.     private int id;  
  3.     private String name;  
  4.     private Department depart;  
  5.   
  6.         ……//set/get方法  
  7. }  
[java]  view plain  copy
  1. public class Skiller extends Employee {  
  2.     private String skill;  
  3.   
  4.         ……//set/get方法  
  5. }  
[java]  view plain  copy
  1. public class Saler extends Employee {  
  2.     private String sale;  
  3.     private int age;  
  4.   
  5.         ……//set/get方法  
  6. }  
[java]  view plain  copy
  1. public class Department {  
  2.     private int id;  
  3.     private String name;  
  4.     private Set<Employee> emps;  
  5.   
  6.         ……//set/get方法  
  7. }  


部门类的映射文件:

[html]  view plain  copy
  1. <class name="Department">  
  2.         <id name="id">  
  3.             <generator class="native"/>  
  4.         </id>  
  5.         <property name="name"/>  
  6.           
  7.         <set name="emps" inverse="true">  
  8.             <key column="depart_id"/>  
  9.             <one-to-many class="Employee"/>  
  10.         </set>  
  11. </class>  

(1)下面关键是员工类的映射文件,我们先来看使用subclass标签的情况:

[html]  view plain  copy
  1. <class name="Employee" discriminator-value="0">  
  2.         <id name="id">  
  3.             <generator class="native"/>  
  4.         </id>  
  5.         <discriminator column="type" type="int"/><!-- 指定了鉴别器 -->  
  6.         <property name="name"/>  
  7.         <many-to-one name="depart" column="depart_id"/>  
  8.           
  9.         <subclass name="Skiller" discriminator-value="1">  
  10.             <property name="skill"/>  
  11.         </subclass>  
  12.         <subclass name="Saler" discriminator-value="2">  
  13.             <property name="sale"/>  
  14.         </subclass>  
  15. </class>  
这种情况就是所谓的将整个继承树映射到同一个表当中,即子类的信息,全部映射到了父类对应的表中。注意,一定要指定鉴别器,它的作用是在父类的映射表中,添加了一个type的列,用来鉴别员工是属于哪个子类,并且在每个类的标签中要指定鉴别器值,如上例中用0表示是普通的员工,用1表示技术人员,用2表示销售人员。我们可以看看创建表的ddl语句:

[sql]  view plain  copy
  1. CREATE TABLE `employee` (  
  2.   `id` int(11) NOT NULL,  
  3.   `type` int(11) NOT NULL,  
  4.   `namevarchar(255) DEFAULT NULL,  
  5.   `depart_id` int(11) DEFAULT NULL,  
  6.   `skill` varchar(255) DEFAULT NULL,  
  7.   `sale` varchar(255) DEFAULT NULL,  
  8.   PRIMARY KEY (`id`),  
  9.   KEY `FK4AFD4ACE972E0614` (`depart_id`),  
  10.   CONSTRAINT `FK4AFD4ACE972E0614` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`)  
  11. ) ENGINE=InnoDB DEFAULT CHARSET=gbk  
用这种方式有缺点有优点,缺点是在表中,会有很多的空值,假如又有了新的子类,那么就要修改表的结构,并且相应的空值会更多;优点是所有信息整合到一张表中,查询的效率高。

下面再来看subclass标签的第二种用法:

[html]  view plain  copy
  1. <class name="Employee" discriminator-value="0"><!--  discriminator-value="0" -->  
  2.         <id name="id">  
  3.             <generator class="native"/>  
  4.         </id>  
  5.         <discriminator column="type" type="int"/><!-- 指定了鉴别器 -->  
  6.         <property name="name"/>  
  7.         <many-to-one name="depart" column="depart_id"/>  
  8.           
  9.         <subclass name="Skiller" discriminator-value="1">  
  10.             <property name="skill"/>  
  11.         </subclass>  
  12.           
  13.         <subclass name="Saler" discriminator-value="2">  
  14.             <join table="saler">  
  15.                 <key column="emp_id"/>  
  16.                 <property name="sale"/>  
  17.             </join>  
  18.         </subclass>  
  19. </class>  
改变的地方,主要是Saler类的标签,在subclass标签中用join标签,这样就为Saler子类单独映射了一个saler表,其主键为父类对应的表的主键。而Skiller类还是和父类映射到了一张表中。来看看Saler创建表的ddl语句:

[sql]  view plain  copy
  1. CREATE TABLE `saler` (  
  2.   `emp_id` int(11) NOT NULL,  
  3.   `sale` varchar(255) DEFAULT NULL,  
  4.   PRIMARY KEY (`emp_id`),  
  5.   KEY `FK682490B3F739201` (`emp_id`),  
  6.   CONSTRAINT `FK682490B3F739201` FOREIGN KEY (`emp_id`) REFERENCES `employee` (`id`)  
  7. ) ENGINE=InnoDB DEFAULT CHARSET=gbk  
需要注意的一个地方是这个表的外键,外键和主键是一样的,都是父类表的主键。


(2)joined-subclass的使用

[html]  view plain  copy
  1. <class name="Employee"><!--  discriminator-value="0" -->  
  2.         <id name="id">  
  3.             <generator class="native"/>  
  4.         </id>  
  5.         <property name="name"/>  
  6.         <many-to-one name="depart" column="depart_id"/>  
  7.   
  8.         <joined-subclass name="Skiller" table="skiller">  
  9.             <key column="emp_id"/>  
  10.             <property name="skill"/>  
  11.         </joined-subclass>  
  12.         <joined-subclass name="Saler" table="saler">  
  13.             <key column="emp_id"/>  
  14.             <property name="sale"/>  
  15.         </joined-subclass>  
  16. </class>  
用joined-subclass只能创建为子类单独创建表,子类对应的表的主键和外键都是其父类的主键。注意,joined-subclass不能和subclass混合使用。


(3)union-subclass的使用

[html]  view plain  copy
  1. <class name="Employee">  
  2.         <id name="id">  
  3.             <generator class="hilo"/>  
  4.         </id>  
  5.         <property name="name"/>  
  6.         <many-to-one name="depart" column="depart_id"/>  
  7.   
  8.         <union-subclass name="Skiller" table="skiller">  
  9.             <property name="skill"/>  
  10.         </union-subclass>  
  11.           
  12.         <union-subclass name="Saler" table="saler">  
  13.             <property name="age"/>  
  14.             <property name="sale"/>  
  15.         </union-subclass>  
  16.     </class>  
注意,这里主键的生成方式就不能是自增的了,这里用的hilo方式,可以为子类的表分配和父类的表不同的主键。这样每个子类生成了一个表,并且结合了父类中的属性。生成的表的ddl语句为:

[sql]  view plain  copy
  1. CREATE TABLE `skiller` (  
  2.   `id` int(11) NOT NULL,  
  3.   `namevarchar(255) DEFAULT NULL,  
  4.   `depart_id` int(11) DEFAULT NULL,  
  5.   `skill` varchar(255) DEFAULT NULL,  
  6.   PRIMARY KEY (`id`),  
  7.   KEY `FK4AFD4ACE972E06147ffd86be` (`depart_id`),  
  8.   CONSTRAINT `FK4AFD4ACE972E06147ffd86be` FOREIGN KEY (`depart_id`) REFERENCES `department` (`id`)  
  9. ) ENGINE=InnoDB DEFAULT CHARSET=gbk  
注意,这里的外键是部门类对应的表的主键,这是和上面两个标签的区别之处。若是将父类设置为抽象类,并且在class标签中设置abstract="true",那么父类就不会生成对应的表了。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值