继承映射策略之----每个子类一张表
在每个子类一张表的映射策略中,每一个子类都有一张属于自己的表,但是这张表只包括了定义在这个子类上面的属性而已,定义在它的父类的属性它的表里面是没有的,所以这样的方式映射的话,就不会浪费一点资源了,每一张表,每一列都是不可少的,也不会出现冗余。这种格式是有点像TABLE_PER_CLASS的策略,只不过这种方案是规范的,没有像TABLE_PER_CLASS一样重复定义列,在这里我们叫它JOINED策略。
按我们的例子,这种策略映射出来的话,数据库的结构将如下所示:
create table Person (
id integer primary key not null,
firstName varchar(255),
lastName varchar(255),
);
create table Customer (
id integer primary key not null,
street varchar(255),
city varchar(255),
state varchar(255),
zip varchar(255),
);
create table Employee (
EMP_PK integer primary key not null,
employeeId integer
);
当持久化管理器加载一个类或者查询一个子类的时候,它必须要对数据库做连接动作,所以我们必须要保存这几张表有一个能够彼此连接起来的列。在我们的例子里面,EMPLOYEE, CUSTOMER, 和 PERSON表共享同样的主键值,这种策略的注释也是挺简单的:
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Person {
}
@Entity
public class Customer extends Person {
}
@Entity
@PrimaryKeyJoinColumn
(name="EMP_PK")
public class Employee extends Customer {
}
在持久化的时候,持久化管理器需要知道每一张表用哪一列来进行连接,所以当我们要指定某一列的时候,就可以用如下注释:
@javax.persistence.PrimaryKeyJoinColumn,它的声明如下:
package javax.persistence;
@Target({TYPE, METHOD, FIELD})
public @interface PrimaryKeyJoinColumn
String name( ) default "";
String referencedColumnName( ) default "";
String columnDefinition( ) default "";
}
name()方法提出你此表中需要用来连接的列的名字,它默认是与父类的主键进行连接,当我们不想与父类的主键进行连接时,我们可以用referencedColumnName( )这个方法来指定你要连接父类的哪个具体的列,它可以被定义为父类的任意列,但是默认是连接父类的主键列,如果从父类到子类的主键名都是一样的,那么这个属性就没必要再设了,因为Customer和Person的主键是一样的,所以在Customer里面不需要定义任何额外的属性,一切默认就可以了,但是由于Employee里面的主键名和其它的不一样,所以它必须显式地声明它的主键是哪一个。如果有的类有复合主键,那么可以用这个注释:
@javax.persistence.PrimaryKeyJoinColumns
package javax.persistence;
@Target({TYPE, METHOD, FIELD})
public @interface PrimaryKeyJoinColumns {
@PrimaryKeyJoinColumn[] value( );
}
它包括了多个@PrimaryKeyJoinColumn的注释。
注意:有些持久化实现这种策略会需要一个辨别器列,虽然大部份是不需要的,所以最好是在使用前查看一下你的持久化提供商的实现说明。
优点:
这种策略虽然没有SINGLE_TABLE策略的速度快,但是你可以定义任何的非空约束在任何的表里面,并且这种模式是规范化的。
缺点:
唯一的缺点就是没有SINGLE_TABLE 策略的性能好。
到现在我们三种处理继承映射的策略都说完了,在不同的场合和环境下选择不同的映射策略是最明智的选择,没有一种策略可以胜任所有场合,否则的话,出一种就可以了,干嘛还出三种呢。希望大家在实际工作中选出适合自己的映射策略,更好的提高工作效率。