Hibernate/JPA中的继承映射 实体extends的关系
Hibernate的继承映射包含了三种不同的策略:
- 每簇类使用一个表;
- 每个子类一个表;
- 每个具体内一个表(有限制)。
假设我们有四个类Animal,Dog,Cat,其代码如下: 文件名:Animal.java
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,映射文件为: 文件名:Animal.hbm.xml
<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>
每个子类一个表
使用每个子类一个表的策略时,可以使用一个映射文件实现,也可以分成多个映射文件来实现。每个子类一个映射文件的情况: 文件名:Animal.hbm.xml
<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的映射。
- 每个具体内一个表(有限制)
使用每个具体内一个表(有限制)策略时,每一个子类的映射文件将要包含所有父类中的属性,映射文件: 文件名:Dog.hbm.xml
<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>
这部分的内容基本与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; import javax.persistence.DiscriminatorType; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType;
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name = "animal_type", discriminatorType = DiscriminatorType.STRING) public class Pet implements Serializable { private int id;
private String name;
private double weight;
public Pet() { }
@Id @GeneratedValue(strategy = GenerationType.AUTO) public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getWeight() { return weight; }
public void setWeight(double weight) { this.weight = weight; }
}
Pet类值的注意的就是通过@Inheritance(strategy = InheritanceType.SINGLE_TABLE)确定采用单表策略,通过@DiscriminatorColumn确定了标志值的字段和类型,我想熟悉hibernate的朋友对这些都应该很熟悉.然后是两个子类:
//Cat.java
package com.denny_blue.ejb3.inheritance;
import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; import javax.persistence.Inheritance; import javax.persistence.InheritanceType;
@Entity @Inheritance(strategy = InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(discriminatorType = DiscriminatorType.STRING) @DiscriminatorValue("cat") public class Cat extends Pet { private String HairBall;
public String getHairBall() { return HairBall; }
public void setHairBall(String hairBall) { HairBall = hairBall; }
}
//Dog.java
package com.denny_blue.ejb3.inheritance;
import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; import javax.persistence.DiscriminatorValue; import javax.persistence.Entity; import javax.persistence.Inheritance; import javax.persistence.InheritanceType;
@Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(discriminatorType=DiscriminatorType.STRING) @DiscriminatorValue("dog") public class Dog extends Pet { private String trick;
public String getTrick() { return trick; }
public void setTrick(String trick) { this.trick = trick; }
}
两个子类最值的关注的就是@DiscriminatorValue注释,比如Cat的此值为cat,意味着当Cat类型的Entity存入数据库时,JPA将自动把cat的值赋给animal_type字段,Dog的值则为dog,由此就可以在同一张表中区分开两个不同的子类.
二.Table per Class
采用Table Per Class策略的话,每个子类都将单独建表,并且都独立拥有基类中的所有属性,互相之间不共享,在我们的例子中所要进行的修改很小,像这样:
//基类
@Entity @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public class Pet implements Serializable { private int id;
private String name;
private double weight;
........
//子类:不需要任何设置
@Entity public class Dog extends Pet { private String trick;
.......
.......
}
例:
@Entity @Table(name = "TEST_A") @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) public class TestA implements java.io.Serializable {
// Fields
/** * */ private static final long serialVersionUID = 5931010626625178698L; private Long id; private String name; private String code;
// Constructors public TestA() {
}
/** minimal constructor */ public TestA(Long id) { this.id = id; }
/** full constructor */ public TestA(Long id, String name, String code) { this.id = id; this.name = name; this.code = code; }
// Property accessors @Id @Column(name = "ID") @GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ") @SequenceGenerator(name="SEQ", sequenceName = "SEQ_TEMP_VOICE_FILE") public Long getId() { return this.id; }
public void setId(Long id) { this.id = id; }
@Column(name = "NAME", unique = false, nullable = true, insertable = true, updatable = true, length = 200) public String getName() { return this.name; }
public void setName(String name) { this.name = name; }
@Column(name = "CODE", unique = false, nullable = true, insertable = true, updatable = true, length = 200) public String getCode() { return this.code; }
public void setCode(String code) { this.code = code; }
}
@Entity @Table(name = "TEST_B") public class TestB extends TestA {
// Fields
/** * */ private static final long serialVersionUID = 4942564072409132522L;
/** minimal constructor */ public TestB() {
} public TestB(Long id) { this.setId(id); }
@Column(name = "FLAG", unique = false, nullable = true, insertable = true, updatable = true, precision = 1, scale = 0) public Long getFlag() { return this.flag; }
public void setFlag(Long flag) { this.flag = flag; }
}
三.Join策略
每个子类同样独立建表,基类也独立建表,只不过所有的子类的表中只有扩展属性,他们共享基类的表,在我们的例子中修改下即可:
//基类
@Entity @Inheritance(strategy = InheritanceType.JOINED) public class Pet implements Serializable { private int id;
private String name;
private double weight;
........
//子类
@Entity
@Inheritance(strategy = InheritanceType.JOINED) public class Dog extends Pet { private String trick;
浙公网安备 33010602011771号