Warning: mysqli_num_fields() expects parameter 1 to be mysqli_result, boolean given in /www/wwwroot/dev.zhalaotie.com/wp-includes/wp-db.php on line 3215

Warning: mysqli_num_fields() expects parameter 1 to be mysqli_result, boolean given in /www/wwwroot/dev.zhalaotie.com/wp-includes/wp-db.php on line 3215
Hibernate继承映射与多态查询 – 扎老铁
Warning: mysqli_num_fields() expects parameter 1 to be mysqli_result, boolean given in /www/wwwroot/dev.zhalaotie.com/wp-includes/wp-db.php on line 3215

Warning: mysqli_num_fields() expects parameter 1 to be mysqli_result, boolean given in /www/wwwroot/dev.zhalaotie.com/wp-includes/wp-db.php on line 3215
Warning: mysqli_num_fields() expects parameter 1 to be mysqli_result, boolean given in /www/wwwroot/dev.zhalaotie.com/wp-includes/wp-db.php on line 3215
class="post-52012 post type-post status-publish format-standard has-post-thumbnail hentry">

Hibernate继承映射与多态查询

一、继承映射关系数据库的表之间不存在继承关系,为了把域模型的继承关系映射到数据库中,Hibernate提供了以下三种对继承关系映射的方法:

  • 每个子类一张表
    
  • 一张表存储继承体系中所有类的信息(该表由继承体系中所有类的属性的并集所映射的字段组成)
    
  • 公共信息放在父类表中,独有信息放在子类表中,每个子类对应一张表,并且子类表通过外键与父类表关联
    

以Person类和Person的两个子类Student、Teacher为例:

Person类:

[java] view plaincopy

  1. public class Person {  
  2.     private Long id;  
  3.     private String name;  
  4.     //省略set、get方法  
  5. }  

Student类:

[java] view plaincopy

  1. public class Student extends Person {  
  2.     private String idCard;  
  3.     //省略set、get方法  
  4. }  

Teacher类:

[java] view plaincopy

  1. public class Teacher extends Person {  
  2.     private Integer salary;  
  3.     //省略set、get方法  
  4. }  

1.每个子类一张表:

(1)保存子类对象时,不必为Person写映射文件,只需为两个子类Student和Teacher编写映射文件;但是保存父类对象时需为父类写映射文件。

(2)子类继承于父类的属性id和name会映射到子类表中,两个子类表没有任何参照关系。

具体配置如下:

Student.hbm.xml:

[html] view plaincopy

  1. <hibernate-mapping>  
  2.     <class name="bean.Student" table="students" >  
  3.         <!–id和name属性是Student继承于父类Person的属性而不是Student独有的属性  –>  
  4.         <id name="id" column="id" type="long">  
  5.             <generator class="increment">  
  6.             </generator>  
  7.         </id>  
  8.         <property name="name" column="student_name" type="string"></property>  
  9.         <property name="idCard" column="idCard" type="string"></property>  
  10.           
  11.     </class>  
  12. </hibernate-mapping>  

Teacher.hbm.xml:

[html] view plaincopy

  1. <hibernate-mapping>  
  2.     <class name="bean.Teacher" table="teachers" >  
  3.         <id name="id" column="id" type="long">  
  4.             <generator class="increment"></generator>  
  5.         </id>  
  6.         <property name="name" column="teacher_name" type="string"></property>  
  7.         <!– salary是Teacher类独有的属性 –>  
  8.         <property name="salary" column="salary" type="integer"></property>  
  9.     </class>  
  10. </hibernate-mapping>  

将两个映射文件加入到主配置文件中:

[html] view plaincopy

  1. <mapping resource="Student.hbm.xml"/>  
  2. <mapping resource="Teacher.hbm.xml"/>  

两表的结构为:

2.用一张表存储继承体系中所有类的信息

(1)子类的信息都存储在这一张表中,表中的字段由所有父类子类的属性的集合映射而成。

(2)表中需要一个字段来标识“这一条记录究竟是属于哪一个子类”

(3)对于某子类没有的属性字段,其子类对象对应的记录的该字段值被填为NULL。

(4)对于这种方式,不需要为子类配置映射文件,只需为父类配置映射文件,因为所有的继承体系的信息都放置在这一张表中。

具体配置如下:

Person.hbm.xml:

[html] view plaincopy

  1.     <class name="bean.Person" table="persons" discriminator-value="Person">  
  2.   
  3.         <id name="id" column="id" type="long">  
  4.             <generator class="increment">  
  5.             </generator>  
  6.         </id>  
  7.         <!– 注意元素的顺序:discriminator要在property的上面 –>  
  8.         <!– discriminator指定判别类的类型的那一个字段的字段名称及数据类型 –>  
  9.         <discriminator column="Type" type="string"></discriminator>  
  10.         <property name="name" column="name" type="string"></property>  
  11.         <!– subclass配置Person的子类,其子元素<property>映射子类的属性,所以不需要为子类单独配置映射文件  
  12.              discriminator-value指定用于分辨子类的Type字段值 —>  
  13.         <subclass name="bean.Student" discriminator-value="Student">  
  14.             <property name="idCard" column="idCard" type="string"></property>  
  15.         </subclass>  
  16.         <subclass name="bean.Teacher" discriminator-value="Teacher">  
  17.             <property name="salary" column="salary" type="integer"></property>  
  18.         </subclass>  
  19.     </class>  
  20. </hibernate-mapping>  

(将Person.hbm.xml加入到主配置文件中,并将Student.hbm.xml和Teacher.hbm.xml从主配置文件中移除)

另外要注意元素的配置顺序,如:dsicriminator配置在property下面时就会出错。

persons表的结构如下:

保存对象:

[java] view plaincopy

  1. Teacher teacher=new Teacher();  
  2. teacher.setName("teacher");  
  3. teacher.setSalary(10000);  
  4. Student student=new Student();  
  5. student.setIdCard("10020711");  
  6. student.setName("student");  
  7. Person person=new Person();  
  8. person.setName("person");  
  9. session.save(person);  
  10. session.save(teacher);  
  11. session.save(student);  

输出的SQL语句为:

[sql] view plaincopy

  1. Hibernate: insert into persons (name, Type, id) values (?, ‘Person’, ?)  
  2. Hibernate: insert into persons (name, salary, Type, id) values (?, ?, ‘Teacher’, ?)  
  3. Hibernate: insert into persons (name, idCard, Type, id) values (?, ?, ‘Student’, ?)  

(可以看出Type字段的值已经确定)

persons表的内容为:

(可以看出某类没有的字段属性值就会被填为NULL,Type字段用于分辨“该记录对应哪个类?“”)

3.公共信息放在父类表中,独有信息放在子类表中,每个子类对应一张表,并且子类表通过外键与父类表关联

(1)与第二种方式相同,只需父类的配置文件Person.hbm.xml

(2)将公共信息即父类中的属性存储在父类表中,将子类的独有的属性存放在子类表中,并且子类表中的主键参照父类表的主键id以便关联父子表获取子类对象中父类属性的值。

(3)与第二种方式配置Person.hbm.xml不同,该方式使用了<joined-subclass元素,如下:

Person.hbm.xml:

[html] view plaincopy

  1. <class name="bean.Person" table="persons">  
  2.   
  3.     <id name="id" column="id" type="long">  
  4.         <generator class="increment"></generator>  
  5.     </id>  
  6.     <property name="name" column="name" type="string"></property>  
  7.     <joined-subclass name="bean.Student" table="students">  
  8.         <!– key元素指定了子类表中的外键(参照父类表的主键id),同时这也是子类表的主键 –>  
  9.         <key column="person_id"></key>  
  10.         <property name="idCard" column="idCard" type="string"></property>  
  11.     </joined-subclass>  
  12.     <joined-subclass name="bean.Teacher" table="teachers">  
  13.         <key column="person_id"></key>  
  14.         <property name="salary" column="salary" type="integer"></property>  
  15.     </joined-subclass>  
  16. </class>  

生成的这三个表的结构及参照关系为:

保存对象后的表的内容为:

二、多态查询:

多态查询指的是在检索当前类时,Hibernate会同时检索当前类的子类,检索结果是当前类及其子类的所有实例。

有网友提出:”get支持多态查询;load只有在lazy=false,才支持多态查询;HQL支持多态查询

以及提出禁用多态查询的方式:将<class>的属性polymorphism改为"explicit"(默认为implicit)

下面我针对上述的三种继承映射的方式编码实分别验证:

保存对象:

[java] view plaincopy

  1. Teacher teacher=new Teacher();  
  2. teacher.setName("teacher");  
  3. teacher.setSalary(10000);  
  4. Student student=new Student();  
  5. student.setIdCard("10020711");  
  6. student.setName("student");  
  7. Person person=new Person();  
  8. person.setName("person");  
  9. session.save(person);  
  10. session.save(teacher);  
  11. session.save(student);  

(1)第一种继承映射方式,即子类各一张表,父类也单独存取在一张表中,且各表之间无任何参照关系,所以当使用get或load查询父类的实例时当然会到父类表中查询了,由于get、load的参数需要id且它们都只返回一个Object,所以这种情况下就不支持多态查询了。

——HQL:支持多态查旬,将父类映射文件(即Person.hbm.xml)的<class>的属性polymorphism改为"explicit"可以“禁用多态查询”。

测试代码:

[java] view plaincopy

  1.  Query query=session.createQuery("from Person");  
  2.  List list = query.list();  
  3.            
  4. for (int i = 0; i < list.size(); i++) {  
  5.     Object object = list.get(i);  
  6.     if (object instanceof Student) {  
  7.         Student s = (Student) object;  
  8.         System.out.println(s.getName() + ":" + s.getIdCard());  
  9.     } else if (object instanceof Teacher) {  
  10.         Teacher t = (Teacher) object;  
  11.         System.out.println(t.getName() + ":" + t.getSalary());  
  12.     }else System.out.println("Person");  
  13. }  

(2)第二种方式的继承映射:所有继承体系的信息都存储在一张表中:

——get方法:支持多态查询,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。

——load方法:将<class>中的lazy属性值改为false后支持多态查询,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。

——HQL:支持多态查旬,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。

测试代码:

[java] view plaincopy

  1.              Query query=session.createQuery("from Person");//测试HQL  
  2.              List list = query.list();  
  3.               
  4.             for (int i = 0; i < list.size(); i++) {  
  5.                 Object object = list.get(i);  
  6.                 if (object instanceof Student) {  
  7.                     Student s = (Student) object;  
  8.                     System.out.println(s.getName() + ":" + s.getIdCard());  
  9.                 } else if (object instanceof Teacher) {  
  10.                     Teacher t = (Teacher) object;  
  11.                     System.out.println(t.getName() + ":" + t.getSalary());  
  12.                 }else System.out.println("Person");  
  13.             }  
  14. //          Person p=(Person)session.get(Person.class, 2L);//测试get  
  15. //          Person p=(Person)session.load(Person.class, 2L);//测试load  
  16. //          System.out.println(p.getName());  
  17. //          if(p instanceof Teacher)  
  18. //          {  
  19. //              Teacher t=(Teacher)p;  
  20. //              System.out.println(t.getSalary());  
  21. //          }else if(p instanceof Student)  
  22. //          {  
  23. //              Student s=(Student)p;  
  24. //              System.out.println(s.getIdCard());  
  25. //          }else  
  26. //              System.out.println("person");  

(3)第三种方式的继承映射:公共信息放在父类表中,子类独有的属性放在子类表中,且通过外键与父类表关联

——get方法:支持多态查询,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。

——load方法:将<class>中的lazy属性值改为false后支持多态查询,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。

——HQL:支持多态查旬,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。

测试代码:

[java] view plaincopy

  1.              Query query=session.createQuery("from Person");//测试HQL  
  2.              List list = query.list();  
  3.               
  4.             for (int i = 0; i < list.size(); i++) {  
  5.                 Object object = list.get(i);  
  6.                 if (object instanceof Student) {  
  7.                     Student s = (Student) object;  
  8.                     System.out.println(s.getName() + ":" + s.getIdCard());  
  9.                 } else if (object instanceof Teacher) {  
  10.                     Teacher t = (Teacher) object;  
  11.                     System.out.println(t.getName() + ":" + t.getSalary());  
  12.                 }else System.out.println("Person");  
  13.             }  
  14. //          Person p=(Person)session.get(Person.class, 2L);//测试get  
  15. //          Person p=(Person)session.load(Person.class, 2L);//测试load  
  16. //          System.out.println(p.getName());  
  17. //          if(p instanceof Teacher)  
  18. //          {  
  19. //              Teacher t=(Teacher)p;  
  20. //              System.out.println(t.getSalary());  
  21. //          }else if(p instanceof Student)  
  22. //          {  
  23. //              Student s=(Student)p;  
  24. //              System.out.println(s.getIdCard());  
  25. //          }else  
  26. //              System.out.println("person");  

(如验证的不正确,请指正)

通过HQL查询表中所有的实体对象

    * HQL语句:session.createQuery("from java.lang.Object").list();

    * 因为所有对象都是继承Object类

发表评论

电子邮件地址不会被公开。