You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

将Hibernate混合继承从hbm.xml迁移至orm.xml的问题

问题描述

Java类层级

Java类层级

需求

将整个类层级存储在名为file的单表中,但SpecialOutFile需要存储在专属的special_file表中。

原HBM.xml实现(可满足需求)

通过hbm.xml映射可以完美实现该需求:

<?xml version="1.0" encoding="UTF-8"?>
<hibernate-mapping xmlns="http://www.hibernate.org/xsd/hibernate-mapping"
                   default-access="field"
                   default-cascade="all"
                   default-lazy="true">

    <class name="com.example.demo.File">
        <id name="id"/>
        <discriminator column="file_type"/>

        <subclass name="com.example.demo.InFile" discriminator-value="InFile"/>
        <subclass name="com.example.demo.TypedOutFile1" discriminator-value="TypedOutFile1"/>
        <subclass name="com.example.demo.TypedOutFile2" discriminator-value="TypedOutFile2"/>
        <subclass name="com.example.demo.OutFile" discriminator-value="OutFile"/>
    </class>

    <class name="com.example.demo.SpecialOutFile" table="special_file">
        <id name="id"/>
        <property name="moreData"/>
    </class>
</hibernate-mapping>
  • 持久化OutFile时,仅在file表插入一条记录;
  • 持久化SpecialOutFile时,仅在special_file表插入一条记录。

Hibernate 6迁移问题

由于Hibernate 6中hbm.xml已被废弃,需迁移至orm.xml,但无法复现相同行为:

  • 当前采用secondary table方式配置时,持久化SpecialOutFile会同时在file和special_file表各插入一条记录:
Hibernate: insert into file (some_data, type, id) values (?, 'SpecialOutFile', ?)
Hibernate: insert into special_file (more_data, id) values (?, ?)

当前orm.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="2.0"
                 xmlns="http://java.sun.com/xml/ns/persistence/orm"
                 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                 xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd">

    <access>FIELD</access>

    <entity class="com.example.demo.File">
        <discriminator-column name="type"/>
        <attributes>
            <id name="id"/>
        </attributes>
    </entity>

    <entity class="com.example.demo.InFile">
        <discriminator-value>InFile</discriminator-value>
    </entity>
    <entity class="com.example.demo.TypedOutFile1">
        <discriminator-value>TypedOutFile1</discriminator-value>
    </entity>
    <entity class="com.example.demo.TypedOutFile2">
        <discriminator-value>TypedOutFile2</discriminator-value>
    </entity>
    <entity class="com.example.demo.OutFile">
        <discriminator-value>OutFile</discriminator-value>
    </entity>

    <entity class="com.example.demo.SpecialOutFile">
        <secondary-table name="special_file"/>
        <attribute-override name="id">
            <column table="special_file"/>
        </attribute-override>
        <attributes>
            <basic name="moreData">
                <column table="special_file"/>
            </basic>
        </attributes>
    </entity>
</entity-mappings>

请问能否将SpecialOutFile的所有继承属性移至secondary table,实现与hbm.xml一致的仅在special_file表存储的效果?


解决方案

不能直接通过secondary table实现该效果,因为JPA的secondary table机制本质是将实体的属性拆分存储到主表和副表,主表必须存在记录,这和你需要的“完全脱离主表、仅存副表”的逻辑冲突。

要在Hibernate 6中复现原hbm.xml的行为,可采用以下方案:

  1. 将SpecialOutFile配置为独立实体
    如果业务允许,直接切断与File的继承关系,把SpecialOutFile定义为独立JPA实体,映射到special_file表,自行维护原继承属性(如id、someData等)。

  2. 使用Hibernate扩展注解实现子类独立表
    若必须保留继承关系,可通过注解而非orm.xml实现:

    • 父类File使用@Inheritance(strategy = InheritanceType.SINGLE_TABLE),指定主表和鉴别器列;
    • 除SpecialOutFile外的子类用@DiscriminatorValue指定鉴别值;
    • SpecialOutFile使用Hibernate扩展的@Subclass注解,配合@Table(name = "special_file")指定单独表,跳过主表写入逻辑。

    对应代码示例:

    @Entity
    @Table(name = "file")
    @Inheritance(strategy = InheritanceType.SINGLE_TABLE)
    @DiscriminatorColumn(name = "type")
    public class File {
        @Id
        private Long id;
        private String someData;
        // getter/setter
    }
    
    @Entity
    @DiscriminatorValue("InFile")
    public class InFile extends File {}
    
    @Entity
    @DiscriminatorValue("TypedOutFile1")
    public class TypedOutFile1 extends File {}
    
    @Entity
    @DiscriminatorValue("TypedOutFile2")
    public class TypedOutFile2 extends File {}
    
    @Entity
    @DiscriminatorValue("OutFile")
    public class OutFile extends File {}
    
    @Entity
    @Table(name = "special_file")
    @Subclass
    public class SpecialOutFile extends File {
        private String moreData;
        // getter/setter
    }
    
  3. ORM.xml替代方案(需调整继承逻辑)
    JPA标准中没有hbm.xml那种“子类完全脱离主表”的映射方式,若必须使用orm.xml,可将File设为@MappedSuperclass,所有子类(包括SpecialOutFile)作为独立实体分别映射到对应表,但会丢失单表继承的鉴别器逻辑,需自行处理类型判断。

总结:最贴近原hbm.xml效果的方案是使用Hibernate扩展的@Subclass注解配合@Table,让SpecialOutFile作为子类但仅写入special_file表。若必须用orm.xml,只能通过将SpecialOutFile设为独立实体来实现需求。


内容的提问来源于stack exchange,提问作者Bastien Jansen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.02 11:55:40