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

是否应将FK设为另一表索引?Hibernate类型字符串关联咨询

解决Hibernate中外键字段通过类型名称关联的问题

你遇到的这个场景,Hibernate完全有成熟的方案来处理——通过建立实体间的关联映射,而不是手动去查询索引值。目前你的代码里把type作为普通字符串属性处理,但实际上它是外键,对应着另一个类型表(比如叫TestType)的主键,正确的做法是让TestCase和这个类型实体建立关联,让Hibernate帮你自动管理外键的存储。

步骤1:创建类型实体(对应你的外键关联表)

首先你需要一个对应类型表的实体,假设你的类型表结构是id(主键)、typeName(类型名称):

public class TestType {
    private int id;
    private String typeName;

    public TestType() {}

    public TestType(String typeName) {
        this.typeName = typeName;
    }

    // getter和setter
    public int getId() { return id; }
    public void setId(int id) { this.id = id; }
    public String getTypeName() { return typeName; }
    public void setTypeName(String typeName) { this.typeName = typeName; }
}

对应的Hibernate XML映射(TestType.hbm.xml):

<hibernate-mapping>
    <class name="com.atp.Model.TestCases.TestType" table="test_types">
        <id name="id" type="int" column="id">
            <generator class="native"/>
        </id>
        <property name="typeName" column="type_name" type="string" unique="true"/>
    </class>
</hibernate-mapping>

步骤2:修改TestCase实体,建立多对一关联

把原来的String type替换成TestType类型的属性,因为一个TestCase对应一个类型,是多对一的关系:

public class TestCase {
    private int id;
    private String name;
    // 替换原来的String type为TestType对象
    private TestType type;
    private byte[] data;
    private String creationDate;
    private String createdBy;

    public TestCase() { }

    // 修改构造器,接收TestType而非String
    public TestCase(String name, TestType type, byte[] data, String creationDate, String createdBy) {
        this.name = name;
        this.type = type;
        this.data = data;
        this.creationDate = creationDate;
        this.createdBy = createdBy;
    }

    // getter和setter
    public TestType getType() { return type; }
    public void setType(TestType type) { this.type = type; }
    // 其他getter、setter保持不变
    ...
}

然后修改TestCase的Hibernate映射文件,把原来的property标签换成many-to-one,指定关联的实体和外键字段:

<hibernate-mapping>
    <class name="com.atp.Model.TestCases.TestCase" table="testCases">
        <meta attribute="class-description">
            This class contains the testCases details.
        </meta>
        <id name="id" type="int" column="idtestCase">
            <generator class="native"/>
        </id>
        <property name="name" column="name" type="string"/>
        <!-- 替换原来的type property为many-to-one关联 -->
        <many-to-one name="type" class="com.atp.Model.TestCases.TestType" column="type" fetch="select">
            <column name="type" not-null="true"/>
        </many-to-one>
        <property name="data" column="data" type="binary"/>
        <property name="creationDate" column="creationDate" type="string"/>
        <property name="createdBy" column="createdBy" type="string"/>
    </class>
</hibernate-mapping>

步骤3:修改addTestCase方法,通过类型名称获取关联实体

现在你可以在添加TestCase时,先根据类型名称从数据库中查询对应的TestType实体,再传入TestCase的构造器——Hibernate会自动把TestType的id存入testCases表的type外键字段:

public static void addTestCase(String testName, String typeName, MultipartFile file, String user) {
    byte[] fileByte;
    Date date = new Date();
    final DateFormat sdf = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
    String creationDate = sdf.format(date);
    try {
        fileByte = file.getBytes();
        
        // 1. 根据类型名称查询TestType实体(这里假设你有获取Session的方法)
        Session session = Database.getSession();
        TestType testType = (TestType) session.createQuery("FROM TestType WHERE typeName = :typeName")
            .setParameter("typeName", typeName)
            .uniqueResult();
        
        // 2. 如果类型不存在,可以选择创建新类型(根据你的业务需求调整)
        if (testType == null) {
            testType = new TestType(typeName);
            session.save(testType);
        }
        
        // 3. 创建TestCase并保存
        TestCase testCase = new TestCase(testName, testType, fileByte, creationDate, user);
        Database.addToDatabase(testCase);
        
        session.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

为什么这样做?

  • 这完全符合ORM的设计思想:用实体对象来表示数据库间的关联,而不是手动处理外键的数值。
  • Hibernate会自动帮你管理外键的插入和查询,不需要你手动去获取索引值。
  • 后续查询TestCase时,你可以直接通过testCase.getType().getTypeName()获取类型名称,不需要额外的关联查询(如果配置了合适的fetch策略)。

如果你实在不想修改实体结构(不推荐),也可以通过自定义Hibernate类型或者使用@Formula注解来映射,但这种方式不够直观,也不符合最佳实践,所以还是建议使用实体关联的方案。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 07:24:26