10.继承映射(hibernate笔记)

一、继承映射的三种策略:

  • 单表继承。一棵类继承树使用一个表(table per class hierachy)
  • 具体表继承。每个子类一个表(table per subclass)
  • 类表继承。每个具体类一个表(table per concrete class)(有一些限制)
    三种策略中的对象模型都是一样的,如下:
10.继承映射(hibernate笔记)_第1张图片
对象模型.png

二、一棵继承树映射成一张表(工程hibernate_extends_1

如:_animal

id name sex weight height type
1 true 100 P
2 false 50 B

2.1、理解如何映射

  • 因为类继承树肯定是对应多个类,要把多个类的信息存放在一张表中,必须有某种机制来区分哪些记录是属于哪个类的。

  • 这种机制就是,在表中添加一个字段(type),用这个字段的值来进行区分。用hibernate实现这种策略的时候,有如下步骤:

    • 父类用普通的标签定义
    • 在父类中定义一个discriminator,即指定这个区分的字段的名称和类型
      如:
    • 子类使用标签定义,在定义subclass的时候,需要注意如下几点:1.Subclass标签的name属性是子类的全路径名;
      2.在Subclass标签中,用discriminator-value属性来标明本子类的discriminator字段(用来区分不同类的字段)的值Subclass标签,既可以被class标签所包含(这种包含关系正是表明了类之间的继承关系),也可以与class标签平行。 当subclass标签的定义与class标签平行的时候,需要在subclass标签中,添加extends属性,里面的值是父类的全路径名称。子类的其它属性,像普通类一样,定义在subclass标签的内部。

2.2、理解如何存储

  • 存储的时候hibernate会自动将鉴别字段值插入到数据库中,在加载数据的时候,hibernate能根据这个鉴别值正确的加载对象.

  • 多态查询:在hibernate加载数据的时候能鉴别出正真的类型(instanceOf),请查看测试类中的各个方法。

    • get支持多态查询
    • load只有在lazy=false,才支持多态查询
    • hql支持多态查询

相关实体类:
Animal.java

private int id;
private String name;
private boolean sex;

Pig.java

private int weight;

Bird.java

private int height;

配置:
extends.java




    
        
            
        
        
        
        
        
        
            
        
        
            
        
    

说明:这里会生成一张表,即表_animal。注意type的类型是hibernate的string类型,不是java的String类型。

测试:
ExtendsTest.java

package cn.itcast.hibernate;
import java.util.Iterator;
import java.util.List;
import org.hibernate.Session;
import junit.framework.TestCase;
public class ExtendsTest extends TestCase {

    public void testSave1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Pig pig = new Pig();
            pig.setName("猪");
            pig.setSex(true);
            pig.setWeight(100);
            session.save(pig);
            
            Bird bird = new Bird();
            bird.setName("鸟");
            bird.setSex(false);
            bird.setHeight(50);
            session.save(bird);
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
    
    /**
     * 采用load,通过Pig查询
     */
    public void testLoad1() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Pig pig = (Pig)session.load(Pig.class, 1);
            System.out.println(pig.getName());
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }
    
    /**
     * 采用load,通过Animal查询
     */
    public void testLoad2() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Animal animal = (Animal)session.load(Animal.class, 1);
            System.out.println(animal.getName());
            
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }           
    
    /**
     * 采用load,通过Animal查询
     */
    public void testLoad3() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Animal animal = (Animal)session.load(Animal.class, 1);
            
            //因为load默认支持lazy,因为我们看到的是Animal的代理对象
            //所以通过instanceof是反应不出正真的对象类型的
            //因此load在默认情况下是不支持多态查询的
            if (animal instanceof Pig) {
                System.out.println(animal.getName());
            }else {
                System.out.println("不是猪");
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }           
    
    /**
     * 采用load,通过Animal查询,将标签上的lazy=false
     */
    public void testLoad4() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            Animal animal = (Animal)session.load(Animal.class, 1);
            //可以正确的判断出Pig的类型,因为lazy=false,返回的是具体的Pig类型
            //此时load支持多态查询
            if (animal instanceof Pig) {
                System.out.println(animal.getName());
            }else {
                System.out.println("不是猪");
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }       
    
    /**
     * 采用get,通过Animal查询
     */
    public void testLoad5() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
            
            //可以正确的判断出Pig的类型,因为返回的是具体的Pig类型
            //get支持多态查询
            Animal animal = (Animal)session.get(Animal.class, 1);

            if (animal instanceof Pig) {
                System.out.println(animal.getName());
            }else {
                System.out.println("不是猪");
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
    
    /**
     * 采用get,通过Animal查询
     */
    public void testLoad6() {
        Session session = null;
        try {
            session = HibernateUtils.getSession();
            session.beginTransaction();
//          List animalList = session.createQuery("from Animal").list();
//          for (Iterator iter = animalList.iterator(); iter.hasNext();) {
//              Animal a = (Animal)iter.next();
//              //能够正确的鉴别出正真的类型,hql是支持多态查询的
//              if (a instanceof Pig) {
//                  System.out.println("是Pig");
//              }else if (a instanceof Bird) {
//                  System.out.println("是bird");
//              } 
//          }
            
            List list = session.createQuery("from java.lang.Object").list();
            for (Iterator iter=list.iterator(); iter.hasNext();) {
                Object o = iter.next();
                if (o instanceof Pig) {
                    System.out.println("是Pig");
                }else if (o instanceof Bird) {
                    System.out.println("是bird");
                } 
            }
            session.getTransaction().commit();
        }catch(Exception e) {
            e.printStackTrace();
            session.getTransaction().rollback();
        }finally {
            HibernateUtils.closeSession(session);
        }
    }   
}

说明:

  • 1.我们可以通过Animal查出相关的子类信息,如方法testLoad2
  • 2.对于方法testLoad3,我们可以看到在lazy默认情况下,我们是不能通过Animal反映出真正的对象类型。也就是load在默认情况下是不支持多态查询的。
  • 3.采用load,通过Animal查询,将标签上的lazy=false。可以看到在方法testLoad4中可以正确判断子类的类型。
  • 4.在方法testLoad5中我们采用get方式通过Animal查询,是可以返回具体的子类类型的。即get支持多态查询。
  • 5.在方法testLoad6中我们使用hql语句进行查询。这里我们试验了两种类型的查询,可以看到hql是支持多态查询的,因为返回的不是代理类,而是具体类。

三、每个子类映射成一张表(工程hibernate_extends_2

10.继承映射(hibernate笔记)_第2张图片
表继承.JPG

说明:其中对象模型不变,只是关系模型变了,于是我们需要重新配置关系模型,而我们的存储加载都不需要改变,而其存储加载的效率不如第一种。而第一种也有缺点,里面有很多冗余字段,而且当将冗余字段设置为非空,那么是存储不进去的。一般情况下采用第一种。

extends.hbm.xml




    
        
            
        
        
        
        
            
            
        
        
            
            
        
    

说明:此时会在数据库中生成三张表。测试的时候和上面例子是一样的,这里不多说。

四、每个具体类映射成一张表(工程hibernate_extends_3

10.继承映射(hibernate笔记)_第3张图片
数据库表.JPG

说明:每个具体类映射成一张表,对象模型还是没有变化。如果使用uuid则相关的存储加载不需要改变,但是如果使用assigned手动分配则存储加载需要做相应的改动,手动设置主键。

extends.hbm.xml




    
        
            
        
        
        
        
            
        
        
            
        
    

说明:此时我们可以看到Animal就不会生成一张表了。同样相关的测试都和上面例子一样,这里不多说。注意映射方式的不同。

最后:比较来看,最后一种方式不能使用自增主键。一般推荐使用第一种。同时我们最后一种方式中需要将animal表设置成abstract="true",这样animal表就不会生成出来,同时不会影响到存储和加载。

你可能感兴趣的:(10.继承映射(hibernate笔记))