(一) 描述
JAVA 中的类之间的关系有两种:
这两种关系,在 hibernate 同样可以映射。
(二) 组合关系
2.1 引入
考虑一个房间类 Class ,房间里面有窗户 Window,窗户有大小,数量,据此设计两个实体类。
2.2 实体类
1 2 3 4 5 6 7 8 9 10 11 12 13
|
@Data public class Room { private Integer id;
private String name;
private Window window; }
|
1 2 3 4 5 6 7 8 9 10 11 12
|
@Data public class Window { private Integer count;
private Integer size; }
|
2.3 思考
我们有两个实体类,但是我们在数据库中只需要一个数据表,这个数据表包括两个实体类的所有属性。通过配置映射文件中的 component 节点实现。
2.4 映射文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xiaobu.learn_hibernate.entity"> <class name="Room" lazy="true" table="room"> <id column="id" name="id"> <generator class="native"/> </id> <property name="name"/>
<component name="window" class="Window"> <property name="count"/> <property name="size"/> </component>
</class> </hibernate-mapping>
|
只需要配置此一个映射文件,就能完成映射。
2.5 测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
|
public class TestComponent extends TestApplication{ @Test public void test(){ Window window = new Window(); window.setCount(6); window.setSize(100);
Room room = new Room(); room.setName("网络工程三班教室"); room.setWindow(window);
Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Serializable key = session.save(room); log.info("key == " + key); tx.commit(); session.close(); } }
|
(三) 继承关系
考虑一个父类 Animal,子类有 Cat,Dog 。。。
3.1 子类直接复写父类属性
子类可以直接复写子类属性,非常简单,不过如果子类多的话会书写复杂。
3.1.1 实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Animal { private Integer id;
private String name; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Cat extends Animal{ private String eatFish; }
|
3.1.2 配置映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xiaobu.learn_hibernate.entity.extend"> <class name="Animal" lazy="true" table="animal" abstract="true"> <id name="id"> <generator class="uuid"/> </id>
<property name="name"/> <property name="eatFish"/> </class> </hibernate-mapping>
|
3.1.3 测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
|
@Test public void testSimple() { Dog dog = new Dog(); dog.setEatBone("吃骨头"); dog.setName("哈士奇");
Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Serializable key = session.save(dog); log.info("key == " + key); tx.commit(); session.close(); }
|
3.2 子类和父类映射到一个数据表
子类可以和父类映射到一个数据表,数据表包括子类和父类所有的属性,并额外增加一个列用来区分不同的子类。这并不符合数据库设计规范,并且只适合子类较少的情况。
3.2.1 实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Animal { private Integer id;
private String name; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Cat extends Animal{ private String eatFish; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Dog extends Animal { private String eatBone; }
|
3.2.2 映射文件
在 xml 映射文件中,需要使用一个 鉴别器 。
用 subclass 节点配置每个子类,并指定鉴别器字段的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xiaobu.learn_hibernate.entity.extend"> <class name="Animal" lazy="true" table="animal"> <id name="id"> <generator class="native"/> </id>
<discriminator column="type_"/>
<property name="name"/>
<subclass name="Cat" discriminator-value="cat_"> <property name="eatFish"/> </subclass>
<subclass name="Dog" discriminator-value="dog_"> <property name="eatBone"/> </subclass> </class> </hibernate-mapping>
|
3.2.3 测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Test public void testDis(){ Dog dog = new Dog(); dog.setName("亚马逊"); dog.setEatBone("吃骨头");
Cat cat = new Cat(); cat.setName("加菲"); cat.setEatFish("吃猫粮");
Session session = HibernateUtil.getSession(); Transaction tx = session.beginTransaction(); Serializable key = session.save(dog); log.info("key == " + key); key = session.save(cat); log.info("key == " + key); tx.commit(); session.close(); }
|
3.3 子类和父类分别映射一个数据表
子类和父类都可以映射到一个数据表,这时候,子类存在一个外键指向父类的主键。
3.3.1 实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Animal { private Integer id;
private String name; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Cat extends Animal{ private String eatFish; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Dog extends Animal { private String eatBone; }
|
3.3.2 映射文件
使用 joined-subclass 节点,将子类和父类担单独映射
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xiaobu.learn_hibernate.entity.extend"> <class name="Animal" lazy="true" table="animal"> <id name="id"> <generator class="native"/> </id>
<property name="name"/>
<joined-subclass name="Cat"> <key column="id"/> <property name="eatFish"/> </joined-subclass>
<joined-subclass name="Dog"> <key column="id"/> <property name="eatBone"/> </joined-subclass> </class> </hibernate-mapping>
|
3.3.3 测试
同上
这种方式会增加 SQL 语句的执行条数。
3.4 只将子类映射到数据表,父类不做映射
3.4.1 实体类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Animal { private String id;
private String name; }
|
1 2 3 4 5 6 7 8 9 10 11 12
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Cat extends Animal{ private String eatFish; }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| package com.xiaobu.learn_hibernate.entity.extend;
import lombok.Data;
@Data public class Dog extends Animal { private String eatBone; }
|
3.4.2 映射文件
将父类设置成 abstract。
使用 union-subclass 配置子类。
注意:使用了 union-subclass 节点不能配置自增长主键,可以使用 UUID 代替。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.xiaobu.learn_hibernate.entity.extend"> <class name="Animal" lazy="true" table="animal" abstract="true"> <id name="id"> <generator class="uuid"/> </id>
<property name="name"/>
<union-subclass name="Cat"> <property name="eatFish"/> </union-subclass>
<union-subclass name="Dog"> <property name="eatBone"/> </union-subclass> </class> </hibernate-mapping>
|
3.4.3 测试
同上
推荐用这种方式。