Inheritance 注释
OpenJPA 是一个基于注释的持久化框架,对持久化的大多数元信息都只需要为实体类提供相应的注释。开发者使用注释描述实体和数据库表之间的映射,也采用注释描述对象继承关系的持久化。javax.persistence.Inheritance 注释用来指定对象继承关系持久化的方式。它的 strategy 属性用于指定持久化对象继承关系在关系数据库中的表现形式,可选择项包括 SINGLE_TABLE、JOINED 和 TABLE_PER_CLASS。它们三个都是 javax.persistence.InheritanceType 中定义的常量。
SINGLE_TABLE
strategy 设置为 SINGLE_TABLE 选项表示所有类及其子类保存在同一个数据库表中,对象的类型使用表中的特殊字段 DTYPE 进行识别。
TABLE_PER_CLASS
strategy 设置为该选项表示每个类使用一个表。
JOINED
strategy 设置为该选项表示父类和子类分别保存在不同的数据库表中,子类中不保存父类对应数据库表中已有的属性,仅通过主键进行关联。
javax.persistence.Inheritance 注释是类级别的注释。需要为每一个成为父类的实体类提供 javax.persistence.Inheritance 注释并且指定 strategy 属性。在同一个企业应用中,开发者可以根据实际情况选择这三种策略中的一种,或者是几种同时使用。
对象继承关系的持久化和查询
上面的章节中,我们已经介绍了 OpenJPA 中处理对象继承的方法,下面我们通过一些简短的代码来演示如何实现 Animal、Fish、Dog 及其继承关系的持久化,同时介绍如何将这种对象继承关系从数据库中还原出来。
演示中,我们选择使用实现第三种方式:JOINED。这也是 OpenJPA 中持久化对象继承的非常好的实践,既符合 Java 开发者面向对象的习惯,也能够符合关系数据库设计的范式要求,而且数据库中的数据冗余最小。TABLE_PER_CLASS 和 SINGLE_TABLE 方式下的对象继承关系持久化的例子请读者参考下面的步骤自己完成。
实体类 Animal
首先我们创建实体类 Animal,它是 Fish 和 Dog 的父类。因此必须为它处理提供 javax.persistence.Inheritance 注释。我们选择使用 JOINED 策略处理继承关系,因此设置 javax.persistence.Inheritance 注释的 strategy 属性为 InheritanceType.JOINED。
清单 1 Animal.java, 继承关系的父类
2. import javax.persistence.Entity;
3. import javax.persistence.Id;
4. import javax.persistence.Inheritance;
5. import javax.persistence.InheritanceType;
6.
7. @Entity
8. @Inheritance(strategy = InheritanceType.JOINED)
9. public class Animal {
10. @Id
11. private int id;
12.
13. private String name;
14.
15. public Animal() {
16. }
17.
18. public Animal(int id, String name) {
19. this.id = id;
20. this.name = name;
21. }
22.
23. public int getId() {
24. return id;
25. }
26.
27. public void setId(int id) {
28. this.id = id;
29. }
30.
31. public String getName() {
32. return name;
33. }
34.
35. public void setName(String name) {
36. this.name = name;
37. }
38.
39. }
实体类 Fish
实体类 Fish 是 Animal 的子类,因此它必须继承自 Animal。同时根据 OpenJPA 的要求,每一个实体必须使用 javax.persistence.Entity 进行注释,因此在 Fish 类声明之前提供 javax.persistence.Entity 注释。
清单 2 Fish.java, 继承关系中的子类
2.
3. import javax.persistence.Entity;
4.
5. @Entity
6. public class Fish extends Animal {
7. /* 鱼的活动范围,比如江、河、湖、海 */
8. private String territory;
9.
10. public Fish() {
11. }
12.
13. public Fish(int id, String name, String territory) {
14. super(id, name);
15. this.territory = territory;
16. }
17.
18. public String getTerritory() {
19. return territory;
20. }
21.
22. public void setTerritory(String territory) {
23. this.territory = territory;
24. }
25.
26. }
实体类 Dog
实体类 Dog 是 Animal 的子类,因此它必须继承自 Animal。和 Fish 类一样,我们需要在 Dog 类声明之前提供 javax.persistence.Entity 注释。
清单 3 Dog.java, 继承关系中的子类
2.
3. import javax.persistence.Entity;
4.
5. @Entity
6. public class Dog extends Animal {
7. /* 性别 */
8. private String sex;
9.
10. public Dog() {
11. }
12.
13. public Dog(int id, String name, String sex) {
14. super(id, name);
15. this.sex = sex;
16. }
17.
18. public String getSex() {
19. return sex;
20. }
21.
22. public void setSex(String sex) {
23. this.sex = sex;
24. }
25.
26. }
创建合适的数据库表
我们可以使用下面的语句创建数据库表:
2 CREATE TABLE DOG(ID INTEGER NOT NULL PRIMARY KEY,SEX VARCHAR(255))
3 CREATE TABLE FISH(ID INTEGER NOT NULL PRIMARY KEY,TERRITORY VARCHAR(255))
4
[注] 使用 OpenJPA 中的 MappingTool 工具可以很容易的保持 Entity 和数据库之间的一致性,也可以使用 MappingTool 工具生成的数据库定义文件(DDL)创建应用正常运行所需要的数据库结构。请参考 OpenJPA 的帮助文档中关于 MappingTool 部分的内容。