hibernate 表映射查询指定列_Hibernate之继承关系与多态查询

3e33d59a4ded00d5dfb115809c4e98f1.png

我们知道在面向对象的Java语言的世界里,对象的组织是有继承和组合两种形式的。当面向对象的概念映射到关系型数据库时,有着这样的对应,类对应了表,对象对应了表行记录,对象属性对应了表列,对象的组合关系对应的是表之间的连接。但是关系型数据库并不能直接表示“继承”这种关系。

想要对象继承在关系型数据库中表达出来,不难看有三种表达方法。

  • 父类单表模式,父类整棵对象继承树的所有属性共用一个表,表会有父类重复冗余的字段和子类冗余的空值字段。
  • 子类单表模式,每个可实例化的子类的继承链上的所有属性共用一个表,表会有父类重复冗余的字段。
  • 连表模式,子类和父类都单独使用各自的表,表中没有冗余字段。

前两种不需要连表,如何选择,本质还是空间vs时间的问题。

根据上面关系型数据库中客观存在的三种表达方法,Hibernate给我们提供了五种模式来映射对象继承关系。我们一起来看看下面这个简单的继承模型,并且观察发生多态查询,也就是调用父类的DAO查询时,它是怎样组织SQL语句的。

f3ed10e04a594c583c3bcb75e795a30b.png
工人有工种属性,经理有要管理工人数量的属性
  • MappedSuperclas —— 简化的子类单表模式
    @MappedSuperclass
    public abstract class Person{
       String name;

       @Id
       @GeneratedValue(strategy = GenerationType.IDENTITY)
       Long id;
    }

    @Entity
    public class Worker extends Person{
        String typeOfWork;
    }

    @Entity
    public class Manager extends Person{
        Long numberOfManageWorker;
    }

这种方式继承则无法进行多态查询,只能查具体子类。这种方式父类要做的事情最少,只需要一个@MappedSuperclas注解,id也可以放在父类,但要注意父类并不是实体。

select id,type_of_work from worker;
select ID,number_of_manage_worker from manager;
  • TABLE_PER_CLASS —— 子类单表模式
    @Entity
    @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
    public abstract class Person{
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long id;
    }

    @Entity
    public class Worker extends Person{
        String typeOfWork;
    }

    @Entity
    public class Manager extends Person{
         Long numberOfManageWorker;
    }

和前一种方式对比父类是实体,可以进行多态查询,查询父类时会union多个子类查询结果作为子查询。classz_用来做类型标记。

select person.id,
       person.name,
       person.number_of_manage_worker,
       person.type_of_work,
       person.clazz_
from (
         select id, name, number_of_manage_worker, null as type_of_work, 1 as clazz_ from manager
         union all
         select id, name, null as number_of_manage_worker, type_of_work, 2 as clazz_ from worker
     ) person
  • SINGLE_TABLE —— 父类单表模式
    @Entity
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn("PERSON_TYPE")//可不写,默认是DTYPE
    public abstract class Person{
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long id;
    }

    @Entity
    @DiscriminatorValue("WORKER")
    public class Worker extends Person{
        String typeOfWork;
    }

    @Entity
    @DiscriminatorValue("MANAGER")
    public class Manager extends Person{
         Long numberOfManageWorker;
    }

这种方式所有子类和父类的字段都放在一个表里,不同的子类实例对应的数据库行记录用默认用DTYPE列区分。

select person.id,
       person.name,
       person.number_of_manage_worker,
       person.type_of_work,
       person.person_type
from person;
  • JOINED —— 连表模式
    @Entity
    @Inheritance(strategy = InheritanceType.JOINED)
    public abstract class Person{
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long id;
    }

    @Entity
    @PrimaryKeyJoinColumn("WORKER_ID")//可以不写指定连接到父类表的列,默认用id列
    public class Worker extends Person{
         String typeOfWork;
    }

    @Entity
    public class Manager extends Person{
         Long numberOfManageWorker;
    }

这种方式把父类和子类分别放到各自的表里面,多态查询时会发生连表。如果不用PrimaryKeyJoinColumn则默认使用id主键列。

select person.id,
       person.name,
       manager.number_of_manage_worker,
       worker.type_of_work,
       case
           when manager.manager_id is not null then 1
           when worker.id is not null then 2
           when person.id is not null then 0 end as clazz_
from person
         left outer join manager on person.id = manager.id
         left outer join worker on person.id = worker.worker_id
  • SecondaryTable —— 混合模式(单表+连表)
    @Entity
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn("PERSON_TYPE")
    public abstract class Person{
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        Long id;
    }

    @Entity
    @DiscriminatorValue("WORKER")
    @SecondaryTable(name = "WORKER",pkJoinColumns = @PrimaryKeyJoinColumn(name = "WORKER_ID"))
    public class Worker extends Person{
         @Column(table = "WORKER")
         String typeOfWork;
    }

    @Entity
    @DiscriminatorValue("MANAGER")
    @SecondaryTable(name = "MANAGER",pkJoinColumns = @PrimaryKeyJoinColumn(name = "MANAGER_ID"))
    public class Manager extends Person{
         @Column(table = "MANAGER")
         Long numberOfManageWorker;
    }

//todo

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值