您的位置:首页 > 其它

Hibernate继承映射与多态查询

2013-03-24 21:31 369 查看
一、继承映射:

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

每个子类一张表


一张表存储继承体系中所有类的信息(该表由继承体系中所有类的属性的并集所映射的字段组成)


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


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

Person类:

public class Person {
private Long id;
private String name;
//省略set、get方法
}


Student类:

public class Student extends Person {
private String idCard;
//省略set、get方法
}


Teacher类:

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>


Teacher.hbm.xml:

<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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: