Hibernate/JPA中的继承映射
Hibernate的继承映射包含了三种不同的策略:
假设我们有四个类Animal,Dog,Cat,其代码如下: class Animal {
private String identifier; private String name; private String category; // setter and getter } 文件名:Dog.java class Dog extends Animal {
private String // setter and getter } 文件名:Cat.java 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> 每个子类一个表的策略实际上一种one-to-one的映射。
使用每个具体内一个表(有限制)策略时,每一个子类的映射文件将要包含所有父类中的属性,映射文件: <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 /** /** minimal constructor */ } @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) |