3
继承映射
3.1
一个继承结构使用一个表(Table per class hierarchy)
这种方法在JPA中是InheritanceType.SINGLE_TABLE。
优点:简单,性能好,是多态操作性能最好的方式。
缺点:子类的字段必须定义成nullable,数据可能不是规范化的,存在数据一致性和易维护问题。
适用:简单继承结构,特别是子类属性比较少的情况。
例子:Billing是父类,CreditCard和BankAccount是两个子类。
@Entity@Inheritance(strategy
=
InheritanceType.SINGLE_TABLE)@DiscriminatorColumn(name
=
"
DISC
"
, discriminatorType
=
DiscriminatorType.STRING)@DiscriminatorValue(
"
BILLING
"
)
public
abstract
class
Billing1
...
{ @Id private int id; private String owner;}
@Entity@DiscriminatorValue(
"
CREDITCARD
"
)
public
class
CreditCard1
extends
Billing1
...
{ private String number;}
@Entity@DiscriminatorValue(
"
BANK
"
)
public
class
BankAccount1
extends
Billing1
...
{ private String account;}
数据库表只有一个:create table
"
BILLING1
"
(
"
DISC
"
VARCHAR(
31
) not
null
,
"
ID
"
INTEGER not
null
,
"
OWNER
"
VARCHAR(
255
),
"
ACCOUNT
"
VARCHAR(
255
),
"
NUMBER
"
VARCHAR(
255
), constraint
"
SYS_PK_1845
"
primary key (
"
ID
"
));create unique index
"
SYS_PK_1845
"
on
"
BILLING1
"
(
"
ID
"
);
3.2
各子类使用单独的表(Table per subclass)
这种方法在JPA中是InheritanceType.JOINED。
优点:数据是规范化的,支持多态查询和多态关联。
缺点:对复杂的继承结构,该方法性能不好。
适用:需要多态查询和多态关联,特别是子类的属性较多的情况。
例子:
@Entity@Inheritance(strategy
=
InheritanceType.JOINED)
public
class
Billing2
...
{ @Id private int id; private String owner;}
@Entity
public
class
CreditCard2
extends
Billing2
...
{ private String number; }
@Entity
public
class
BankAccount2
extends
Billing2
...
{ private String account;}
数据库表是:create table
"
BILLING2
"
(
"
ID
"
INTEGER not
null
,
"
OWNER
"
VARCHAR(
255
), constraint
"
SYS_PK_1846
"
primary key (
"
ID
"
));create unique index
"
SYS_PK_1846
"
on
"
BILLING2
"
(
"
ID
"
);create table
"
CREDITCARD2
"
(
"
ID
"
INTEGER not
null
,
"
NUMBER
"
VARCHAR(
255
), constraint
"
SYS_PK_1874
"
primary key (
"
ID
"
));alter table
"
CREDITCARD2
"
add constraint
"
FK4FC2E7898F29E03D
"
foreign key (
"
ID
"
) references
"
BILLING2
"
(
"
ID
"
);create unique index
"
SYS_PK_1874
"
on
"
CREDITCARD2
"
(
"
ID
"
);create index
"
SYS_IDX_1944
"
on
"
CREDITCARD2
"
(
"
ID
"
);create table
"
BANKACCOUNT2
"
(
"
ID
"
INTEGER not
null
,
"
ACCOUNT
"
VARCHAR(
255
), constraint
"
SYS_PK_1842
"
primary key (
"
ID
"
));alter table
"
BANKACCOUNT2
"
add constraint
"
FKDB157E218F29E03D
"
foreign key (
"
ID
"
) references
"
BILLING2
"
(
"
ID
"
);create unique index
"
SYS_PK_1842
"
on
"
BANKACCOUNT2
"
(
"
ID
"
);create index
"
SYS_IDX_1904
"
on
"
BANKACCOUNT2
"
(
"
ID
"
);
3.3
支持多态的各具体实体类使用单独的表(Table per concrete class with implicit polymorphism)。
优点:比较简单。
缺点:对多态关联的支持不好,多态查询也有问题(一个多态查询需要对应多条查询语句)。
适用:复杂继承结构中的顶层结构(一般不需要多态操作),并且基类修改的可能性不大的情况。特别适用于不采用JPA接口(如JDBC)的查询。
例子:
@MappedSuperclass
public
class
Billing3
...
{ private String owner;}
@Entity
public
class
CreditCard3
extends
Billing3
...
{ @Id private int id; private String number;}
@Entity
public
class
BankAccount3
extends
Billing3
...
{ @Id private int id; private String account;}
数据库表是:create table
"
CREDITCARD3
"
(
"
ID
"
INTEGER not
null
,
"
OWNER
"
VARCHAR(
255
),
"
NUMBER
"
VARCHAR(
255
), constraint
"
SYS_PK_1875
"
primary key (
"
ID
"
));create unique index
"
SYS_PK_1875
"
on
"
CREDITCARD3
"
(
"
ID
"
);create table
"
BANKACCOUNT3
"
(
"
ID
"
INTEGER not
null
,
"
OWNER
"
VARCHAR(
255
),
"
ACCOUNT
"
VARCHAR(
255
), constraint
"
SYS_PK_1843
"
primary key (
"
ID
"
));create unique index
"
SYS_PK_1843
"
on
"
BANKACCOUNT3
"
(
"
ID
"
);
3.4
采用Union的各具体实体类使用单独的表(Table per concrete class with unions)
这种方式在JPA中是InheritanceType.TABLE_PER_CLASS。
优点:支持多态查询和多态关联。
缺点:TABLE_PER_CLASS在JPA中是可选的,也就是说不能保证每个EJB 3.0的容器都支持这种方式。
适用:如果需要考虑可移植性问题,不推荐使用本方法。
例子:
@Entity@Inheritance(strategy
=
InheritanceType.TABLE_PER_CLASS)
public
class
Billing4
...
{ @Id private int id; private String owner;}
@Entity
public
class
CreditCard4
extends
Billing4
...
{ private String number;}
@Entity
public
class
BankAccount4
extends
Billing4
...
{ private String account;}
数据库表是:create table
"
BILLING4
"
(
"
ID
"
INTEGER not
null
,
"
OWNER
"
VARCHAR(
255
), constraint
"
SYS_PK_1847
"
primary key (
"
ID
"
));create unique index
"
SYS_PK_1847
"
on
"
BILLING4
"
(
"
ID
"
);create table
"
CREDITCARD4
"
(
"
ID
"
INTEGER not
null
,
"
OWNER
"
VARCHAR(
255
),
"
NUMBER
"
VARCHAR(
255
), constraint
"
SYS_PK_1876
"
primary key (
"
ID
"
));create unique index
"
SYS_PK_1876
"
on
"
CREDITCARD4
"
(
"
ID
"
);create table
"
BANKACCOUNT4
"
(
"
ID
"
INTEGER not
null
,
"
OWNER
"
VARCHAR(
255
),
"
ACCOUNT
"
VARCHAR(
255
), constraint
"
SYS_PK_1844
"
primary key (
"
ID
"
));create unique index
"
SYS_PK_1844
"
on
"
BANKACCOUNT4
"
(
"
ID
"
);
由于Billing类不是抽象类,所以数据库中有Billing4表;可以将Billing设计为abstract,则不会出现Billing4表。
任何一种映射方法可以从抽象类继承,也可以从实体类继承;但是JPA规范不允许从接口继承(Hibernate支持从接口继承)。另外,还可以混用继承方法,例如采用一个继承结构使用一个表,但是某个表采用各子类使用单独的表方法。最后,在选用不同的继承映射方法前,请考虑是否可以采用设计模式将继承转化为合成,使业务模型更趋简单。
本文的最后一部分将描述实体和实体的关联关系。