现在的位置: 首页 > 综合 > 正文

Hibernate继承映射与多态查询

2017年11月30日 ⁄ 综合 ⁄ 共 7068字 ⁄ 字号 评论关闭

一、继承映射:

关系数据库的表之间不存在继承关系,为了把域模型的继承关系映射到数据库中,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

抱歉!评论已关闭.