Hibernate/JPA中的继承映射
假设我们有四个类Animal,Dog,Cat,其代码如下:
class
Animal
{
private String identifier; private String name; private String category; // setter and getter }
class
Dog extends Animal
{
private String // setter and getter }
class
Cat extends Animal
{
private String // setter and getter }
使用每簇类使用一个表的策略时,有一个限制就时子类不能有NOT NULL,映射文件为:
<
class
name
="Animal"
table
="TB_ANIMAL"
>
< id name ="identifier" type ="string" column ="IDENTIFIER" > < generator class ="uuid.hex" /> </ id > < discriminator column ="ANIMAL_TYPE" type ="string" /> < property name ="name" column ="NAME" type ="string" /> < subclass name ="Dog" discriminator-value ="DOG" > </ subclass > < subclass name ="Cat" discriminator-value ="CAT" > </ subclass > </ class >
使用每个子类一个表的策略时,可以使用一个映射文件实现,也可以分成多个映射文件来实现。每个子类一个映射文件的情况:
<
class
name
="Animal"
table
="ANIMAL"
>
< id name ="identifier" column ="IDENTIFIER" type ="string" > < generator class ="uuid.hex" /> </ id > < property > </ class > 文件名:Dog.hbm.xml < joined-subclass name ="Dog" table ="DOG" extends ="Animal" > < key column ="DOG_ID" /> </ joined-subclass > 文件名:Cat.hbm.xml < joined-subclass name ="Cat" table ="CAT" extends ="Cat" > < key column ="CAT_ID" /> </ joined-subclass >
使用每个具体内一个表(有限制)策略时,每一个子类的映射文件将要包含所有父类中的属性,映射文件:
<
class
name
="Dog"
table
="DOG"
>
< id name ="identifier" column ="IDENTIFIER" type ="string" > < generator class ="uuid.hex" /> </ id > < property name ="name" column ="NAME" type ="string" /> </ class > 文件名:Cat.hbm.xml < class name ="Cat" table ="CAT" > < id name ="identifier" column ="IDENTIFIER" type ="string" > < generator class ="uuid.hex" /> </ id > < property name ="name" column ="NAME" type ="string" /> </ class >
JPA中的实体层次设计这部分的内容基本与Hibernate一致.JPA同样支持3种类型的继承形式: 1.Single Table Strategy ,单表策略,一张表包含基类与子类的所有数据,很多情况下都是采用这样的冗余设计,通过一个discriminator来区分 2.Table Per Class Strategy ,每个子类对应一张表,每张表都拥有基类的属性 3.Join Strategy ,仍然是每个子类对应一张表,但此表中不包含基类的属性,仅仅是此子类的扩展属性,共享基类的属性
以一个例子来说明3种情况: 一.单表策略 比如Pet作为基类,Cat和Dog继承此类并拥有自己的扩展属性,如: package com.denny_blue.ejb3.inheritance; import java.io.Serializable; import javax.persistence.DiscriminatorColumn; @Entity private String name; private double weight; public Pet() { @Id public void setId(int id) { public String getName() { public void setName(String name) { public double getWeight() { public void setWeight(double weight) { } Pet类值的注意的就是通过@Inheritance(strategy = InheritanceType.SINGLE_TABLE)确定采用单表策略,通过@DiscriminatorColumn确定了标志值的字段和类型,我想熟悉hibernate的朋友对这些都应该很熟悉.然后是两个子类: //Cat.java package com.denny_blue.ejb3.inheritance; import javax.persistence.DiscriminatorColumn; @Entity public String getHairBall() { public void setHairBall(String hairBall) { } //Dog.java package com.denny_blue.ejb3.inheritance; import javax.persistence.DiscriminatorColumn; @Entity public String getTrick() { public void setTrick(String trick) { } 两个子类最值的关注的就是@DiscriminatorValue注释,比如Cat的此值为cat,意味着当Cat类型的Entity存入数据库时,JPA将自动把cat的值赋给animal_type字段,Dog的值则为dog,由此就可以在同一张表中区分开两个不同的子类.
二.Table per Class 采用Table Per Class策略的话,每个子类都将单独建表,并且都独立拥有基类中的所有属性,互相之间不共享,在我们的例子中所要进行的修改很小,像这样: //基类 @Entity private String name; private double weight; ........ //子类:不需要任何设置 @Entity ....... ....... } 例: @Entity // Fields /** // Constructors } /** minimal constructor */ /** full constructor */ // Property accessors public void setId(Long id) { @Column(name = "NAME", unique = false, nullable = true, insertable = true, updatable = true, length = 200) public void setName(String name) { @Column(name = "CODE", unique = false, nullable = true, insertable = true, updatable = true, length = 200) public void setCode(String code) { } @Entity // Fields /**
} @Column(name = "FLAG", unique = false, nullable = true, insertable = true, updatable = true, precision = 1, scale = 0) public void setFlag(Long flag) { }
三.Join策略 每个子类同样独立建表,基类也独立建表,只不过所有的子类的表中只有扩展属性,他们共享基类的表,在我们的例子中修改下即可: //基类 @Entity private String name; private double weight; ........ //子类 @Entity @Inheritance(strategy = InheritanceType.JOINED) |