一、继承映射:
关系数据库的表之间不存在继承关系,为了把域模型的继承关系映射到数据库中,Hibernate提供了以下三种对继承关系映射的方法:
每个子类一张表
一张表存储继承体系中所有类的信息(该表由继承体系中所有类的属性的并集所映射的字段组成)
公共信息放在父类表中,独有信息放在子类表中,每个子类对应一张表,并且子类表通过外键与父类表关联
以Person类和Person的两个子类Student、Teacher为例:
Person类:
public class Person { private Long id; private String name; //省略set、get方法 }
public class Student extends Person { private String idCard; //省略set、get方法 }
public class Teacher extends Person { private Integer salary; //省略set、get方法 }
1.每个子类一张表:
(1)保存子类对象时,不必为Person写映射文件,只需为两个子类Student和Teacher编写映射文件;但是保存父类对象时需为父类写映射文件。
(2)子类继承于父类的属性id和name会映射到子类表中,两个子类表没有任何参照关系。
具体配置如下:
Student.hbm.xml:
<hibernate-mapping> <class name="bean.Student" table="students" > <!--id和name属性是Student继承于父类Person的属性而不是Student独有的属性 --> <id name="id" column="id" type="long"> <generator class="increment"> </generator> </id> <property name="name" column="student_name" type="string"></property> <property name="idCard" column="idCard" type="string"></property> </class> </hibernate-mapping>
<hibernate-mapping> <class name="bean.Teacher" table="teachers" > <id name="id" column="id" type="long"> <generator class="increment"></generator> </id> <property name="name" column="teacher_name" type="string"></property> <!-- salary是Teacher类独有的属性 --> <property name="salary" column="salary" type="integer"></property> </class> </hibernate-mapping>将两个映射文件加入到主配置文件中:
<mapping resource="Student.hbm.xml"/> <mapping resource="Teacher.hbm.xml"/>两表的结构为:
2.用一张表存储继承体系中所有类的信息
(1)子类的信息都存储在这一张表中,表中的字段由所有父类子类的属性的集合映射而成。
(2)表中需要一个字段来标识“这一条记录究竟是属于哪一个子类”
(3)对于某子类没有的属性字段,其子类对象对应的记录的该字段值被填为NULL。
(4)对于这种方式,不需要为子类配置映射文件,只需为父类配置映射文件,因为所有的继承体系的信息都放置在这一张表中。
具体配置如下:
Person.hbm.xml:
<class name="bean.Person" table="persons" discriminator-value="Person"> <id name="id" column="id" type="long"> <generator class="increment"> </generator> </id> <!-- 注意元素的顺序:discriminator要在property的上面 --> <!-- discriminator指定判别类的类型的那一个字段的字段名称及数据类型 --> <discriminator column="Type" type="string"></discriminator> <property name="name" column="name" type="string"></property> <!-- subclass配置Person的子类,其子元素<property>映射子类的属性,所以不需要为子类单独配置映射文件 discriminator-value指定用于分辨子类的Type字段值 --> <subclass name="bean.Student" discriminator-value="Student"> <property name="idCard" column="idCard" type="string"></property> </subclass> <subclass name="bean.Teacher" discriminator-value="Teacher"> <property name="salary" column="salary" type="integer"></property> </subclass> </class> </hibernate-mapping>(将Person.hbm.xml加入到主配置文件中,并将Student.hbm.xml和Teacher.hbm.xml从主配置文件中移除)
另外要注意元素的配置顺序,如:dsicriminator配置在property下面时就会出错。
persons表的结构如下:
保存对象:
Teacher teacher=new Teacher(); teacher.setName("teacher"); teacher.setSalary(10000); Student student=new Student(); student.setIdCard("10020711"); student.setName("student"); Person person=new Person(); person.setName("person"); session.save(person); session.save(teacher); session.save(student);输出的SQL语句为:
Hibernate: insert into persons (name, Type, id) values (?, 'Person', ?) Hibernate: insert into persons (name, salary, Type, id) values (?, ?, 'Teacher', ?) 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:
<class name="bean.Person" table="persons"> <id name="id" column="id" type="long"> <generator class="increment"></generator> </id> <property name="name" column="name" type="string"></property> <joined-subclass name="bean.Student" table="students"> <!-- key元素指定了子类表中的外键(参照父类表的主键id),同时这也是子类表的主键 --> <key column="person_id"></key> <property name="idCard" column="idCard" type="string"></property> </joined-subclass> <joined-subclass name="bean.Teacher" table="teachers"> <key column="person_id"></key> <property name="salary" column="salary" type="integer"></property> </joined-subclass> </class>生成的这三个表的结构及参照关系为:
保存对象后的表的内容为:
二、多态查询:
多态查询指的是在检索当前类时,Hibernate会同时检索当前类的子类,检索结果是当前类及其子类的所有实例。
有网友提出:”get支持多态查询;load只有在lazy=false,才支持多态查询;HQL支持多态查询“
以及提出禁用多态查询的方式:将<class>的属性polymorphism改为"explicit"(默认为implicit)
下面我针对上述的三种继承映射的方式编码实分别验证:
保存对象:
Teacher teacher=new Teacher(); teacher.setName("teacher"); teacher.setSalary(10000); Student student=new Student(); student.setIdCard("10020711"); student.setName("student"); Person person=new Person(); person.setName("person"); session.save(person); session.save(teacher); session.save(student);
(1)第一种继承映射方式,即子类各一张表,父类也单独存取在一张表中,且各表之间无任何参照关系,所以当使用get或load查询父类的实例时当然会到父类表中查询了,由于get、load的参数需要id且它们都只返回一个Object,所以这种情况下就不支持多态查询了。
——HQL:支持多态查旬,将父类映射文件(即Person.hbm.xml)的<class>的属性polymorphism改为"explicit"可以“禁用多态查询”。
测试代码:
Query query=session.createQuery("from Person"); List list = query.list(); for (int i = 0; i < list.size(); i++) { Object object = list.get(i); if (object instanceof Student) { Student s = (Student) object; System.out.println(s.getName() + ":" + s.getIdCard()); } else if (object instanceof Teacher) { Teacher t = (Teacher) object; System.out.println(t.getName() + ":" + t.getSalary()); }else System.out.println("Person"); }
(2)第二种方式的继承映射:所有继承体系的信息都存储在一张表中:
——get方法:支持多态查询,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。
——load方法:将<class>中的lazy属性值改为false后支持多态查询,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。
——HQL:支持多态查旬,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。
测试代码:
Query query=session.createQuery("from Person");//测试HQL List list = query.list(); for (int i = 0; i < list.size(); i++) { Object object = list.get(i); if (object instanceof Student) { Student s = (Student) object; System.out.println(s.getName() + ":" + s.getIdCard()); } else if (object instanceof Teacher) { Teacher t = (Teacher) object; System.out.println(t.getName() + ":" + t.getSalary()); }else System.out.println("Person"); } // Person p=(Person)session.get(Person.class, 2L);//测试get // Person p=(Person)session.load(Person.class, 2L);//测试load // System.out.println(p.getName()); // if(p instanceof Teacher) // { // Teacher t=(Teacher)p; // System.out.println(t.getSalary()); // }else if(p instanceof Student) // { // Student s=(Student)p; // System.out.println(s.getIdCard()); // }else // System.out.println("person");
(3)第三种方式的继承映射:公共信息放在父类表中,子类独有的属性放在子类表中,且通过外键与父类表关联
——get方法:支持多态查询,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。
——load方法:将<class>中的lazy属性值改为false后支持多态查询,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。
——HQL:支持多态查旬,但是将<class>的属性polymorphism改为"explicit"不能“禁用多态查询”。
测试代码:
Query query=session.createQuery("from Person");//测试HQL List list = query.list(); for (int i = 0; i < list.size(); i++) { Object object = list.get(i); if (object instanceof Student) { Student s = (Student) object; System.out.println(s.getName() + ":" + s.getIdCard()); } else if (object instanceof Teacher) { Teacher t = (Teacher) object; System.out.println(t.getName() + ":" + t.getSalary()); }else System.out.println("Person"); } // Person p=(Person)session.get(Person.class, 2L);//测试get // Person p=(Person)session.load(Person.class, 2L);//测试load // System.out.println(p.getName()); // if(p instanceof Teacher) // { // Teacher t=(Teacher)p; // System.out.println(t.getSalary()); // }else if(p instanceof Student) // { // Student s=(Student)p; // System.out.println(s.getIdCard()); // }else // System.out.println("person");
通过HQL查询表中所有的实体对象
* HQL语句:session.createQuery("from java.lang.Object").list();
* 因为所有对象都是继承Object类
转载请注明出处:http://blog.csdn.net/jialinqiang/article/details/8711508