Hibernate 映射继承关系

Company类和Employee类之间为一对多的双向关联关系,假设Employee有两个子类HourlyEmployee类和SalariedEmployee类, 此时Employee类为抽象类,不能被实例化。Employee类和HourlyEmployee类、SalariedEmployee类之间为继承关系, HourlyEmployee类和SalariedEmployee类继承自Employee类。

对于继承关系,以下介绍三种方式来将其映射到关系数据库。

1.继承关系树的每个具体类对应一个表

数据库表为:

create table COMPANIES (
   ID bigint not null,
   NAME varchar(15),
   primary key (ID)
);
create table HOURLY_EMPLOYEES (
   ID bigint not null,
   NAME varchar(15),
   RATE double precision,
   COMPANY_ID bigint,
   primary key (ID),

   foreign key (COMPANY_ID) references COMPANIES (ID)

);
create table SALARIED_EMPLOYEES (
   ID bigint not null,
   NAME varchar(15),
   SALARY double precision,
   COMPANY_ID bigint,
   primary key (ID),

   foreign key (COMPANY_ID) references COMPANIES (ID)

);

HourlyEmployee类和HOURLY_EMPLOYEES表对应,SalariedEmployee类和SALARIED_EMPLOYEES表对应。

Company类、HourlyEmployee类和SalariedEmployee类都有相应的映射文件,而Employee类没有相应的映射文件。

由于关系数据模型没有描述Employee类和它的两个子类的继承关系,因此无法映射Company类的employees集合。

Company.java:

public class Company implements Serializable {
    private Long id;
    private String name;
    private Set employees=new HashSet();

    Constructor..; getter..; setter..;

}

Company.hbm.xml:

<hibernate-mapping >
  <class name="mypack.Company" table="COMPANIES" >
    <id name="id" type="long" column="ID">
      <generator class="increment"/>
    </id>

    <property name="name" type="string"  column="NAME" />
  </class>
</hibernate-mapping>


Employee.java:

abstract public class Employee implements Serializable {
    private Long id;
    private String name;
    private Company company;

    Constructor..; getter..; setter..;

}

HourlyEmployee.java:

public class HourlyEmployee extends Employee{
    private double rate;

    Constructor..; getter..; setter..;

}

HourlyEmployee.hbm.xml:

<hibernate-mapping >
   <class name="mypack.HourlyEmployee" table="HOURLY_EMPLOYEES">
      <id name="id" type="long" column="ID">
        <generator class="increment"/>
      </id>
   
      <property name="name" type="string" column="NAME" />
      <property name="rate" column="RATE" type="double" />

      <many-to-one
        name="company"
        column="COMPANY_ID"
        class="mypack.Company"
      />

    </class>
</hibernate-mapping>

SalariedEmployee.java:

public class SalariedEmployee extends Employee {
    private double salary;

   Constructor..; getter..; setter..;

}


SalariedEmployee.hbm.xml:

<hibernate-mapping >
   <class name="mypack.SalariedEmployee" table="SALARIED_EMPLOYEES">
      <id name="id" type="long" column="ID">
        <generator class="increment"/>
      </id>
   
      <property name="name" type="string" column="NAME" />
      <property name="salary" column="SALARY" type="double" />

      <many-to-one
        name="company"
        column="COMPANY_ID"
        class="mypack.Company"
      />

    </class>
</hibernate-mapping>

这种情况下,不能直接进行以下查询:

session.createQuery("from Employee").list();

2.继承关系树的根类对应一个表

只需为Employee类创建一张表EMPLOYEES,该表需要额外加入一个EMPLOYEE_TYPE字段,用于区分Employee的具体类型。

数据库表为:

create table COMPANIES (
   ID bigint not null,
   NAME varchar(15),
   primary key (ID)
);
create table EMPLOYEES (
   ID bigint not null,
   NAME varchar(15),
   EMPLOYEE_TYPE varchar(2),
   RATE double precision,
   SALARY double precision,
   COMPANY_ID bigint,
   primary key (ID) foreign key (COMPANY_ID) references COMPANIES (ID)
);

Company类和Employee类有相应的映射文件,而HourlyEmployee类和SalariedEmployee类没有相应的映射文件。

Company.java:

public class Company implements Serializable {
    private Long id;
    private String name;
    private Set employees=new HashSet();

   Constructor..; getter..; setter..;

}

Company.hbm.xml:

<hibernate-mapping >
  <class name="mypack.Company" table="COMPANIES" >
    <id name="id" type="long" column="ID">
      <generator class="increment"/>
    </id>

    <property name="name" type="string"  column="NAME" />
    <set
        name="employees"
        inverse="true">
        <key column="COMPANY_ID" />
        <one-to-many class="mypack.Employee" />
     </set>   

  </class>
</hibernate-mapping>

Employee.java:

abstract public class Employee implements Serializable {
    private Long id;
    private String name;
    private Company company;

   Constructor..; getter..; setter..;

}

HourlyEmployee.java:

public class HourlyEmployee extends Employee{
    private double rate;

   Constructor..; getter..; setter..;

}

SalariedEmployee.java:

public class SalariedEmployee extends Employee {
    private double salary;

   Constructor..; getter..; setter..;

}

Employee.hbm.xml:

<hibernate-mapping >
   <class name="mypack.Employee" table="EMPLOYEES">
      <id name="id" type="long" column="ID">
        <generator class="increment"/>
      </id>
      <discriminator column="EMPLOYEE_TYPE" type="string"  />  
      <property name="name" type="string" column="NAME" />

      <many-to-one
        name="company"
        column="COMPANY_ID"
        class="mypack.Company"
      />

      <subclass name="mypack.HourlyEmployee" discriminator-value="HE" >
         <property name="rate" column="RATE" type="double" />
      </subclass>

      <subclass name="mypack.SalariedEmployee" discriminator-value="SE" >
         <property name="salary" column="SALARY" type="double" />
      </subclass>
     
    </class>
</hibernate-mapping>

<discriminator>元素指定EMPLOYEES表中用于区分Employee类型的字段EMPLOYEE_TYPE,<subclass>元素用于映射HourlyEmployee类和SalariedEmployee类,discriminator-value属性指定EMPLOYEE_TYPE字段的取值。

如果Employee累不是抽象类,本身可实例化,可在<class>元素中定义其discriminator值:

<class name="mypack.Employee" table="EMPLOYEES"discriminator-value="EE">

当进行以下查询时:

session.createQuery("fromHourlyEmployee").list();

Hibernate执行的SQL语句为:

select * from EMPLOYEES whereEMPLOYEE_TYPE='HE';

3.继承关系树的每个类对应一个表

EMPLOYEES表仅包含和Employee类的属性对应的字段,HE表仅包含和HourlyEmployee类的属性对应的字段,SE表仅包含和SalariedEmployee类的属性对应的字段。HE表和SE表都以EMPLOYEE_ID作为主键,该字段同时作为外键参照EMPLOYEES表

数据库表为:

create table COMPANIES (
   ID bigint not null,
   NAME varchar(15),
   primary key (ID)
);
create table EMPLOYEES (
   ID bigint not null,
   NAME varchar(15),
   COMPANY_ID bigint,
   primary key (ID),

   foreign key (COMPANY_ID) references COMPANIES (ID)

);

create table HOURLY_EMPLOYEES (
   EMPLOYEE_ID bigint not null,
   RATE double precision,
   primary key (EMPLOYEE_ID),

   foreign key (EMPLOYEE_ID) references EMPLOYEES (ID)

);

create table SALARIED_EMPLOYEES (
   EMPLOYEE_ID bigint not null,
   SALARY double precision,
   primary key (EMPLOYEE_ID),

   foreign key (EMPLOYEE_ID) references EMPLOYEES (ID)

);

Company类和Employee类有相应的映射文件,而HourlyEmployee类和SalariedEmployee类没有相应的映射文件。

Company.java:

public class Company implements Serializable {
    private Long id;
    private String name;
    private Set employees=new HashSet();

   Constructor..; getter..; setter..;

}

Company.hbm.xml:

<hibernate-mapping >
  <class name="mypack.Company" table="COMPANIES" >
    <id name="id" type="long" column="ID">
      <generator class="increment"/>
    </id>

    <property name="name" type="string"  column="NAME" />
    <set
        name="employees"
        inverse="true">
        <key column="COMPANY_ID" />
        <one-to-many class="mypack.Employee" />
     </set>   

  </class>
</hibernate-mapping>

Employee.java:

abstract public class Employee implements Serializable {
    private Long id;
    private String name;
    private Company company;

   Constructor..; getter..; setter..;

}

HourlyEmployee.java:
public class HourlyEmployee extends Employee{
    private double rate;

   Constructor..; getter..; setter..;

}

SalariedEmployee.java:

public class SalariedEmployee extends Employee {
    private double salary;

   Constructor..; getter..; setter..;

}

Employee.hbm.xml:

<hibernate-mapping >
   <class name="mypack.Employee" table="EMPLOYEES">
      <id name="id" type="long" column="ID">
        <generator class="increment"/>
      </id>
      <property name="name" type="string" column="NAME" />

      <many-to-one
        name="company"
        column="COMPANY_ID"
        class="mypack.Company"
      />

      <joined-subclass name="mypack.HourlyEmployee" table="HOURLY_EMPLOYEES" >
         <key column="EMPLOYEE_ID" />
         <property name="rate" column="RATE" type="double" />
      </joined-subclass>

      <joined-subclass name="mypack.SalariedEmployee"  table="SALARIED_EMPLOYEES" >
         <key column="EMPLOYEE_ID" />
         <property name="salary" column="SALARY" type="double" />
      </joined-subclass>
     
    </class>
</hibernate-mapping>

<joined-subclass>元素用于映射Employee类的两个子类的属性。

当进行以下查询时:

session.createQuery("fromHourlyEmployee").list();

Hibernate执行的SQL语句为:

select * fromHOURLY_EMPLOYEES he inner join EMPLOYEESe on he.EMPLOYEE_ID = e.ID;

当进行以下查询时:

session.createQuery("fromEmployee").list();

Hibernate执行的SQL语句为:

select * fromEMPLOYEES e

left outer joinHOURLY_EMPLOYEES he on he.EMPLOYEE_ID = e.ID

left outer join SALARIED_EMPLOYEES se on se.EMPLOYEE_ID = e.ID;

4.映射复杂继承关系

下图为一棵复杂的继承关系树,其中DOClass类为抽象类,其他均为具体类。

可将其分解为三棵子树:

DOClass、ClassA和ClassB为一棵子树,DOClass为抽象类,通常不会对其进行多态查询,因此可采用每个具体类对应一个表的映射方式,ClassA对应TABLE_A表,ClassB对应TABLE_B表。

ClassA、ClassC、ClassD、ClassG和ClassH为一棵子树,ClassA的所有子类均只包含少量属性,因此可采用根类对应一个表的映射方式,ClassA对应TABLE_A表

ClassB、ClassE和ClassF为一棵子树,ClassB的两个子类均包含很多属性,因此可采用每个类对应一个表的映射方式, ClassB对应TABLE_B表ClassE对应TABLE_E表ClassF对应TABLE_F表

因此,只需创建TABLE_A、TABLE_B、TABLE_E和TABLE_F四张表即可,其中TABLE_A包含DOClass、ClassA、ClassC、ClassD、ClassG和ClassH的属性所对应的字段,TABLE_B包含DOClass和ClassB的属性所对应的字段,TABLE_E和TABLE_F的B_ID字段即使主键,又是参照TABLE_B的外键。

数据库表为:

create table TABLE_A (
   ID bigint not null,
   A1 varchar(15),
   C1 varchar(15),
   D1 varchar(15),
   G1 varchar(15),
   H1 varchar(15),
   A_TYPE char(1),
   primary key (ID)
);

create table TABLE_B (
   ID bigint not null,
   B1 varchar(15),
   primary key (ID)
);
create table TABLE_E (
   B_ID bigint not null,
   E1 varchar(15),
   E2 varchar(15),
   E3 varchar(15),
   E4 varchar(15),
   E5 varchar(15),
   E6 varchar(15),
   primary key (B_ID),

   foreign key (B_ID) references TABLE_B(ID)

);

create table TABLE_F (
   B_ID bigint not null,
   F1 varchar(15),
   F2 varchar(15),
   F3 varchar(15),
   F4 varchar(15),
   F5 varchar(15),
   F6 varchar(15),
   F7 varchar(15),
   primary key (B_ID),

   foreign key (B_ID) references TABLE_B(ID)

);

DOClass.java、ClassA.java...ClassH.java均是普通的pojo,只包含其各自属性(如ClassA只包含a1属性)、Constructor以及getter、setter方法。

只需创建ClassA和ClassB的映射文件即可。

ClassA.hbm.xml:

<hibernate-mapping >
   <class name="mypack.ClassA" table="TABLE_A" discriminator-value="A" >
      <id name="id" type="long" column="ID">
        <generator class="increment"/>
      </id>
      <discriminator column="A_TYPE" type="string"  />  
      <property name="a1" type="string" column="A1" />

      <subclass name="mypack.ClassC" discriminator-value="C" >
         <property name="c1" column="C1" type="string" />
      </subclass>

      <subclass name="mypack.ClassD" discriminator-value="D" >
        <property name="d1" column="D1" type="string" />
 
        <subclass name="mypack.ClassG" discriminator-value="G" >
           <property name="g1" column="G1" type="string" />
        </subclass>
        
        <subclass name="mypack.ClassH" discriminator-value="H" >
           <property name="h1" column="H1" type="string" />
        </subclass>

      </subclass>
    </class>
</hibernate-mapping>


ClassB.hbm.xml:

<hibernate-mapping >
   <class name="mypack.ClassB" table="TABLE_B">
      <id name="id" type="long" column="ID">
        <generator class="increment"/>
      </id>
      <property name="b1" type="string" column="B1" />

      <joined-subclass name="mypack.ClassE"  table="TABLE_E">
         <key column="B_ID" />
         <property name="e1" column="E1" type="string" />
         <property name="e2" column="E2" type="string" />
         <property name="e3" column="E3" type="string" />
         <property name="e4" column="E4" type="string" />
         <property name="e5" column="E5" type="string" />
         <property name="e6" column="E6" type="string" />
      </joined-subclass >

      <joined-subclass name="mypack.ClassF"  table="TABLE_F">
         <key column="B_ID" />
         <property name="f1" column="F1" type="string" />
         <property name="f2" column="F2" type="string" />
         <property name="f3" column="F3" type="string" />
         <property name="f4" column="F4" type="string" />
         <property name="f5" column="F5" type="string" />
         <property name="f6" column="F6" type="string" />
      </joined-subclass >
    </class>
</hibernate-mapping>

注: 在<subclass>元素中只能嵌入 <subclass>子元素,而不能嵌入 <joined-subclass>子元素,而在 <joined-subclass>元素中只能嵌入 <joined-subclass>子元素,而不能嵌入 <subclass>子元素

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值