【Hibernate 5】继承映射配置及多态查询

来源:互联网 发布:创业公司取名 知乎 编辑:程序博客网 时间:2024/06/04 07:22

一、继承实现的三种策略

1.1,单表继承。每棵类继承树使用一个表(table per class hierarchy) ——>本文主要介绍的继承策略

类继承树对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。这种机制就是,在表中添加一个字段,用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:
1,父类用普通的<class>标签定义,在父类中定义一个discriminator,即指定这个区分的字段的名称和类型
如:<discriminator column=”XXX” type=”string”/>
2,子类使用<subclass>标签定义,在定义subclass的时候,需要注意如下几点:Subclass标签的name属性是子类的全路径名;在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)的值;Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在subclass标签的内部。

PS:唯一字段隔离,也就是所谓的type,通过type确定子类的类型,每条数据中包含了需要的所有信息字段


1.2,每个具体类一个表(table per concrete class)(有一些限制)

这种策略使用joined-subclass标签来定义子类。父类、子类,每个类都对应一张数据库表。在父类对应的数据库表中,实际上会存储所有的记录,包括父类和子类的记录;在子类对应的数据库表中,这个表只定义了子类中所特有的属性映射的字段。子类与父类,通过相同的主键值来关联。实现这种策略的时候,有如下步骤:
1,父类用普通的<class>标签定义即可,父类不再需要定义discriminator字段
2,子类用<joined-subclass>标签定义,在定义joined-subclass的时候,需要注意如下几点:Joined-subclass标签的name属性是子类的全路径名;Joined-subclass标签需要包含一个key标签,这个标签指定了子类和父类之间是通过哪个字段来关联的。如:<key column=”PARENT_KEY_ID”/>,这里的column,实际上就是父类的主键对应的映射字段名称。
3,Joined-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当Joined-subclass标签的定义与class标签平行的时候,需要在Joined-subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在joined-subclass标签的内部。

PS:表隔离,每个表中都只有属于自身对应的属性,如果要获取完整的数据,则需要通过外键联合查询


1.3,具体表继承。每个子类一个表(table per subclass) 

这种策略使用union-subclass标签来定义子类。每个子类对应一张表,而且这个表的信息是完备的,即包含了所有从父类继承下来的属性映射的字段(这就是它跟joined-subclass的不同之处,joined-subclass定义的子类的表,只包含子类特有属性映射的字段)。实现这种策略的时候,有如下步骤:
1,父类用普通<class>标签定义即可

2,子类用<union-subclass>标签定义,在定义union-subclass的时候,需要注意如下几点:Union-subclass标签不再需要包含key标签(与joined-subclass不同);Union-subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当Union-subclass标签的定义与class标签平行的时候,需要在Union-subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在Union-subclass标签的内部。这个时候,虽然在union-subclass里面定义的只有子类的属性,但是因为它继承了父类,所以,不需要定义其它的属性,在映射到数据库表的时候,依然包含了父类的所有属性的映射字段。

PS:表隔离,与每个具体类不同的是,这种策略只会为每个具体的子类生成表单,而在每个表单里,既包含了父类的属性,又包含了自身的属性。当需要查询一条完整数据的时候,不需要联合外键!


二、实例介绍继承映射

2.1,建立实体类和映射

Animal类:

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.hibernate;public class Animal {private int id;private String name;private boolean sex;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 boolean isSex() {return sex;}public void setSex(boolean sex) {this.sex = sex;}}</span>

Bird类:

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.hibernate;public class Bird extends Animal {private int height;public int getHeight() {return height;}public void setHeight(int height) {this.height = height;}}</span>

Pig类:

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.hibernate;public class Pig extends Animal {private int weight;public int getWeight() {return weight;}public void setWeight(int weight) {this.weight = weight;}}</span>

映射文件:

<span style="font-family:KaiTi_GB2312;font-size:18px;"><?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><class name="com.angel.hibernate.Animal" table="t_animal" lazy="false"><id name="id"><generator class="native" /></id><!-- 加入鉴别标签,且必须放在id后面 --><discriminator column="type" type="string"/><property name="name" /><property name="sex" type="boolean" /><subclass name="com.angel.hibernate.Pig" discriminator-value="P"><property name="weight" /></subclass><subclass name="com.angel.hibernate.Bird" discriminator-value="B"><property name="height" /></subclass></class></hibernate-mapping> </span>

2.2,测试类

<span style="font-family:KaiTi_GB2312;font-size:18px;">package com.angel.hibernate;import org.hibernate.Session;import junit.framework.TestCase;public class test_extend extends TestCase {public void testSave() {Session session = null;try {// 创建session对象session = HibernateUtils.getSession();// 开启事务session.beginTransaction();Pig pig = new Pig();pig.setName("daddy pig");pig.setSex(true);pig.setWeight(200);session.save(pig);Bird bird = new Bird();bird.setName("mummy bird");bird.setSex(true);bird.setHeight(100);session.save(bird);session.getTransaction().commit();} catch (Exception e) {e.printStackTrace();session.getTransaction().rollback();} finally {HibernateUtils.closeSession(session);}}public void testLoad(){Session session=null;try {session = HibernateUtils.getSession();session.beginTransaction();Animal a = (Animal)session.load(Animal.class, 1);//load默认支持lazy,所以我们看到的是Animal的代理,采用instanceof无法鉴别出真正的类型Pig//如果想要load支持多态查询,则需要将lazy值设置为falseif (a instanceof Pig) {System.out.println(a.getName());}else {System.out.println("不是猪!");}session.getTransaction().commit();} catch (Exception e) {e.printStackTrace();session.getTransaction().rollback();}finally {HibernateUtils.closeSession(session);}}}</span>

三、多态查询

多态查询:hibernate在加载数据的时候,能够采用instancof鉴别出其真正的类型

在Hibernate中,支持多台查询的有:get、Hql。而对于load,因为其默认支持延迟加载lazy,所以它不支持多态查询,返回的只是一个代理值。如果想要让load支持多态查询,则需要在配置文件中将其lazy属性设置为false。


四、总结

继承映射在实际运用中还是很广泛中,在做这个例子的时候,突然想起来多租户数据隔离的三个策略,其实跟这个差不多。额,说明我脑袋里还是装东西了嘛。然后对于继承映射的三种策略,可以看出的是,单表继承是比较简单而且效率高的,只需要维护一个表。而具体表策略则需要进行外键维护等,相对来说单表继承是一个比较好的选择!

0 0
原创粉丝点击