继承关系映射
继承关系映射分为三种:
整个继承结构映射一张表
每个类映射一张表
有多少个类就映射多少张表,包括子类父类
每个具体子类映射一张表
只需要每个子类映射一张表,而父类不映射到表
用到的例子
在研究继承关系映射时,我们用到了一个继承关系的例子。
父类:BillingDetails(账单明细)
id:Long
owner:String(拥有者)
code:String(卡号)
created:Date(创建时间)
setter、getter方法
子类:BankAccount(银行账户)
bankName:String(银行名称)
bankSwift:String(银行的简称)
子类:CreditCard(信用卡)
type:String(信用卡类型)
expMonth:String(有效时间,月份)
expYear:String(有效时间,年份)
BillingDetails类
package com.li.inheritance.pojo;
import java.io.Serializable;
import java.util.Date;
public class BillingDetails implements Serializable{
private Long id;
private String owner;
private String code;
private Date created;
public BillingDetails() {
super();
}
public BillingDetails(Long id, String owner, String code, Date created) {
super();
this.id = id;
this.owner = owner;
this.code = code;
this.created = created;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getOwner() {
return owner;
}
public void setOwner(String owner) {
this.owner = owner;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
@Override
public String toString() {
return "BillingDetails [id=" + id + ", owner=" + owner + ", code=" + code + ", created=" + created + "]";
}
}
CreditCard类
package com.li.inheritance.pojo;
import java.io.Serializable;
import java.util.Date;
public class CreditCard extends BillingDetails implements Serializable {
private String Type;
private String expMonth;
private String expYear;
public CreditCard() {}
public CreditCard(Long id, String owner, String code, Date created, String type, String expMonth, String expYear) {
/*调用父类的构造方法*/
super(id, owner, code, created);
Type = type;
this.expMonth = expMonth;
this.expYear = expYear;
}
public String getType() {
return Type;
}
public void setType(String type) {
Type = type;
}
public String getExpMonth() {
return expMonth;
}
public void setExpMonth(String expMonth) {
this.expMonth = expMonth;
}
public String getExpYear() {
return expYear;
}
public void setExpYear(String expYear) {
this.expYear = expYear;
}
@Override
public String toString() {
return "CreditCard [Type=" + Type + ", expMonth=" + expMonth + ", expYear=" + expYear + "]";
}
}
BankAccount类
package com.li.inheritance.pojo;
import java.io.Serializable;
import java.util.Date;
public class BankAccount extends BillingDetails implements Serializable {
private String bankName;
private String bankSwift;
public BankAccount() {}
public BankAccount(Long id, String owner, String code, Date created, String bankName, String bankSwift) {
super(id, owner, code, created);
this.bankName = bankName;
this.bankSwift = bankSwift;
}
public String getBankName() {
return bankName;
}
public void setBankName(String bankName) {
this.bankName = bankName;
}
public String getBankSwift() {
return bankSwift;
}
public void setBankSwift(String bankSwift) {
this.bankSwift = bankSwift;
}
@Override
public String toString() {
return "BankAccount [bankName=" + bankName + ", bankSwift=" + bankSwift + "]";
}
}
整个映射结构映射到一张表
此方式支持多态,根据父类查找一个子类信息能查找到
表结构
CREATE TABLE t_hierarchy(
id NUMBER(10) PRIMARY KEY,
owner VARCHAR2(15),
code VARCHAR2(15),
created DATE,
bankname VARCHAR2(20),
bankswift VARCHAR2(20),
credit_card_type VARCHAR2(20),
expired_month VARCHAR2(20),
expired_year VARCHAR2(20),
account_type VARCHAR2(20)
);
这张表结构存储了整个继承结构的内容,包含了父类和子类的内容,而最后一列 “account_type” 用以区分记录的来源,记录可以来源于父类(BilliingDetails),也可以是子类BankAccount、子类CreditCard,我们把此列作为一个标识。
映射文件
discriminator-value:每个类的唯一标识,区分记录的来源
discriminator:name属性标明表中用来区分记录来源的栏位,type指明了类型,如下:如果ACCOUNT_TYPE的值为CC,则说明该记录是通过CreditCard映射过来的
subclass:配置子类
主键生成策略只需配置父类即可,主键也在父类中
<class name="BillingDetails" table="t_hierarchy" discriminator-value="BD">
...
<discriminator column="ACCOUNT_TYPE" type="string"/>
...
<subclass name="CreditCard" discriminator-value="CC">...</subclass>
<subclass name="BankAccount" discriminator-value="BA">...</subclass>
</class>
hierarchy.hbm.xml映射文件,完成之后配置到核心配置文件中
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="com.li.inheritance.pojo.BillingDetails" table="T_HIERARCHY" discriminator-value="BD">
<id name="id" column="ID" type="long">
<generator class="assigned"></generator>
</id>
<discriminator column="ACCOUNT_TYPE" type="string"></discriminator>
<property name="owner" column="OWNER" type="string"></property>
<property name="code" column="CODE" type="string"></property>
<property name="created" column="CREATED" type="string"></property>
<subclass name="com.li.inheritance.pojo.CreditCard" discriminator-value="CC">
<property name="type" column="CREDIT_CARD_TYPE" type="string"></property>
<property name="expMonth" column="EXPIRED_MONTH" type="string"></property>
<property name="expYear" column="EXPIRED_YEAR" type="string"></property>
</subclass>
<subclass name="com.li.inheritance.pojo.BankAccount" discriminator-value="BA">
<property name="bankName" column="BANKNAME" type="string"></property>
<property name="bankSwift" column="BANKSWIFT" type="string"></property>
</subclass>
</class>
</hibernate-mapping>
测试
package com.li.inheritance.pojo;
import java.util.Date;
import org.hibernate.Session;
import org.hibernate.Transaction;
import com.li.common.HibernateSessionFactory;
public class HierarchyTest {
public static void main(String[] args) {
BillingDetails bd=new BillingDetails();
bd.setId(123L);
bd.setCode("111");
bd.setOwner("Lin");
bd.setCreated(new Date(System.currentTimeMillis()));
BankAccount ba=new BankAccount();
ba.setBankName("ChinaBank");
ba.setBankSwift("cnb");
ba.setCreated(new Date(System.currentTimeMillis()));
ba.setId(456L);
ba.setCode("222");
ba.setOwner("White");
CreditCard cc=new CreditCard();
cc.setId(789L);
cc.setCode("333");
cc.setOwner("Lucy");
cc.setCreated(new Date(System.currentTimeMillis()));
cc.setExpMonth("6");
cc.setExpYear("2018");
Session session = HibernateSessionFactory.getSession();
Transaction trans=null;
try {
trans=session.beginTransaction();
session.save(bd);
session.save(ba);
session.save(cc);
BillingDetails account=(BillingDetails) session.get(BankAccount.class, 456L);
/*多态,下面这种方式能通过父类查找到子类*/
BillingDetails account=(BillingDetails) session.get(BillingDetails.class, 456L);
System.out.println(account);
trans.commit();
} catch (Exception e) {
e.printStackTrace();
trans.rollback();
}
}
}
数据库记录
改进
实际上我们创建一个父类(BillingDetails)对象并持久化到数据库中没有任何意义,因为子类就包括了父类的所有信息,而父类映射到数据库中没有实际意义,所以我们通常将父类声明为抽象类,那么我们就不能是哟 new 关键字来实例化父类了。
每个类映射一张表
此方式支持多态,根据父类查找一个子类信息能查找到
表结构
表名中间加join是因为我们的操作中有join操作。我们把子表中的主键又作为外键映射到父表中的主键,实现了表与表的关联。
t_join_billingdetails表(父表)
CREATE TABLE t_join_billingdetails(
id NUMBER(10) PRIMARY KEY,
owner VARCHAR2(15),
code VARCHAR2(15),
created DATE
);
t_join_bankaccount表(子表)
CREATE TABLE t_join_bankaccount(
billing_id NUMBER(10) PRIMARY KEY,
bankname VARCHAR2(20),
bankswift VARCHAR2(20),
FOREIGN KEY(billing_id) REFERENCES t_join_billingdetails(id)
);
t_join_creditcard表(子表)
CREATE TABLE t_join_creditcard(
billing_id NUMBER(10) PRIMARY KEY,
credit_card_type VARCHAR2 (20),
expired_month VARCHAR2 (20),
expired_year VARCHAR2 (20),
FOREIGN KEY(billing_id) REFERENCES t_join_billingdetails(id)
);
映射文件
join.hbm.xml映射文件,完成之后配置到核心配置文件中
其中key标签设置表对应的外键列。
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.li.inheritance.pojo">
<class name="BillingDetails" table="T_JOIN_BILLINGDETAILS">
<id name="id" column="ID" type="long">
<generator class="assigned"></generator>
</id>
<property name="owner" column="OWNER" type="string"></property>
<property name="code" column="CODE" type="string"></property>
<property name="created" column="CREATED" type="string"></property>
<joined-subclass name="CreditCard" table="T_JOIN_CREDITCARD">
<key column="BILLING_ID"/>
<property name="type" column="CREDIT_CARD_TYPE" type="string"></property>
<property name="expMonth" column="EXPIRED_MONTH" type="string"></property>
<property name="expYear" column="EXPIRED_YEAR" type="string"></property>
</joined-subclass>
<joined-subclass name="BankAccount" table="T_JOIN_BANKACCOUNT">
<key column="BILLING_ID"/>
<property name="bankName" column="BANKNAME" type="string"></property>
<property name="bankSwift" column="BANKSWIFT" type="string"></property>
</joined-subclass>
</class>
</hibernate-mapping>
每个具体子类映射一张表
此方式不支持多态,根据父类查找一个子类信息不能查找到
表结构
concrete:混泥土,表示具体的意思
t_concrete_bankaccount表
CREATE TABLE t_concrete_bankaccount(
id NUMBER(10) PRIMARY KEY,
owner VARCHAR2(15),
code VARCHAR2(15),
created DATE,
bankname VARCHAR2(20),
bankswift VARCHAR2(20)
);
t_concrete_creditcard表
CREATE TABLE t_concrete_bankaccount(
id NUMBER(10) PRIMARY KEY,
owner VARCHAR2(15),
code VARCHAR2(15),
created DATE,
credit_card_type VARCHAR2(20),
expired_month VARCHAR2(20),
expired_year VARCHAR2(20)
);
映射文件
concrete.hbm.xml
最外层的class指定父类,但是父类不映射表结构,所有无需配置对应的表,还配置对应的主键生成策略和属性。
对子类我们使用union-subclass来配置,子类独有的属性我们需要配置在子类中
完成映射文件,再把映射文件配置到核心配置文件中hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="com.li.inheritance.pojo">
<class name="BillingDetails">
<id name="id" column="ID" type="long">
<generator class="assigned"></generator>
</id>
<property name="owner" column="OWNER" type="string"></property>
<property name="code" column="CODE" type="string"></property>
<property name="created" column="CREATED" type="string"></property>
<union-subclass name="CreditCard" table="T_CONCRETE_CREDITCARD">
<property name="type" column="CREDIT_CARD_TYPE" type="string"></property>
<property name="expMonth" column="EXPIRED_MONTH" type="string"></property>
<property name="expYear" column="EXPIRED_YEAR" type="string"></property>
</union-subclass>
<union-subclass name="BankAccount" table="T_CONCRETE_BANKACCOUNT">
<property name="bankName" column="BANKNAME" type="string"></property>
<property name="bankSwift" column="BANKSWIFT" type="string"></property>
</union-subclass>
</class>
</hibernate-mapping>
继承关系小结
分类 | 多态 | 更新维护 | 出具报表 |
---|---|---|---|
整个继承结构映射一张表 | 支持 | 难 | 易 |
每个类映射一张表 | 支持 | 易 | 难 |
每个具体子类映射一张表 | 不支持 | 难 | 易 |
多态:即一张表中存储多种类型的记录
不支持多态的用的不多,其中第二种用的更多一点