0

0

Hibernate 自引用多对多关系映射:构建父子关联的正确姿势

聖光之護

聖光之護

发布时间:2025-11-01 15:25:01

|

763人浏览过

|

来源于php中文网

原创

Hibernate 自引用多对多关系映射:构建父子关联的正确姿势

本教程详细阐述了在 hibernate 中如何正确映射自引用多对多关系,以处理同一实体(如 `test`)之间的复杂父子关联。通过利用 `@manytomany` 和 `@jointable` 注解,我们将展示如何在一个中间关联表(`relation`)中双向定义父集合和子集合,从而实现灵活且高效的数据模型。

在复杂的业务场景中,我们经常会遇到实体之间存在自引用关系的情况,例如组织架构中的上下级关系、社交网络中的关注关系,或者本文将讨论的通用父子关系。当这种自引用关系是多对多时(一个父节点可以有多个子节点,一个子节点也可以有多个父节点),如何在 Hibernate 中进行准确且高效的映射,是许多开发者面临的挑战。本教程将以 Test 实体为例,详细讲解如何通过 @ManyToMany 和 @JoinTable 注解,在一个中间关联表中实现自引用多对多关系的双向映射。

数据库模型解析

首先,我们来看一下涉及的数据库表结构。我们有两个核心表:test_table 和 relation。

  1. test_table (主实体表)

    • id: 主键,自增,非空。
    • comment: 描述信息。

    这是一个典型的实体表,代表了我们系统中需要建立父子关联的独立单元。

  2. relation (中间关联表)

    • id: 主键,自增。
    • a_id: 外键,关联到 test_table 的 id 列,并存在索引。
    • a_parent_id: 外键,关联到 test_table 的 id 列,并存在索引。
    • (a_id, a_parent_id): 联合唯一约束,确保一对父子关系不会重复。

    relation 表是实现多对多关系的关键。a_id 和 a_parent_id 共同定义了一个父子对。例如,如果 a_id = 3 且 a_parent_id = 1,则表示 Test 实体 id 为 3 的是 Test 实体 id 为 1 的子节点。

    Miniflow
    Miniflow

    AI工作流自动化平台

    下载

Hibernate 实体映射实践

现在,我们将 test_table 映射到 Hibernate 的 Test 实体。目标是让 Test 实体能够方便地访问其所有父节点和子节点。

基础 Test 实体结构

首先是 Test 实体的基本映射:

import javax.persistence.*;
import java.util.List;

@Entity
@Table(name = "test_table")
public class Test {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false)
    private Long id;

    @Column
    private String comment;

    // 父节点集合将在此处定义
    private List parents;

    // 子节点集合将在此处定义
    private List children;

    // Getters and Setters
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getComment() {
        return comment;
    }

    public void setComment(String comment) {
        this.comment = comment;
    }

    public List getParents() {
        return parents;
    }

    public void setParents(List parents) {
        this.parents = parents;
    }

    public List getChildren() {
        return children;
    }

    public void setChildren(List children) {
        this.children = children;
    }
}

映射父节点集合 (parents)

要映射一个 Test 实例的所有父节点,我们需要告诉 Hibernate 如何通过 relation 表找到它们。对于一个 Test 实例(比如 id=X),其父节点是 relation 表中 a_id 列为 X 的记录对应的 a_parent_id。

    @ManyToMany(targetEntity = Test.class)
    @JoinTable(
        name = "relation", // 中间关联表的名称
        joinColumns = @JoinColumn(name = "a_id", referencedColumnName = "id"), // 当前实体(Test)在关联表中的外键列
        inverseJoinColumns = @JoinColumn(name = "a_parent_id", referencedColumnName = "id") // 关联实体(Parent Test)在关联表中的外键列
    )
    private List parents;
  • @ManyToMany(targetEntity = Test.class): 指明这是一个多对多关系,并且关联的目标实体是自身 (Test.class),这定义了自引用特性。
  • @JoinTable(name = "relation"): 指定了用于维护此多对多关系的中间表是 relation。
  • joinColumns = @JoinColumn(name = "a_id", referencedColumnName = "id"):
    • name = "a_id": 表示在 relation 表中,a_id 列是当前 Test 实体(即子节点)的 ID。
    • referencedColumnName = "id": 表示 a_id 列引用的是 Test 实体(test_table)的 id 列。
  • inverseJoinColumns = @JoinColumn(name = "a_parent_id", referencedColumnName = "id"):
    • name = "a_parent_id": 表示在 relation 表中,a_parent_id 列是关联的父 Test 实体(即父节点)的 ID。
    • referencedColumnName = "id": 表示 a_parent_id 列引用的是 Test 实体(test_table)的 id 列。

映射子节点集合 (children)

映射一个 Test 实例的所有子节点与映射父节点类似,但 joinColumns 和 inverseJoinColumns 的角色需要互换。对于一个 Test 实例(比如 id=Y),其子节点是 relation 表中 a_parent_id 列为 Y 的记录对应的 a_id。

    @ManyToMany(targetEntity = Test.class)
    @JoinTable(
        name = "relation", // 中间关联表的名称
        joinColumns = @JoinColumn(name = "a_parent_id", referencedColumnName = "id"), // 当前实体(Test)在关联表中的外键列
        inverseJoinColumns = @JoinColumn(name = "a_id", referencedColumnName = "id") // 关联实体(Child Test)在关联表中的外键列
    )
    private List children;
  • joinColumns = @JoinColumn(name = "a_parent_id", referencedColumnName = "id"):
    • name = "a_parent_id": 表示在 relation 表中,a_parent_id 列是当前 Test 实体(即父节点)的 ID。
    • referencedColumnName = "id": 表示 a_parent_id 列引用的是 Test 实体(test_table)的 id 列。
  • inverseJoinColumns = @JoinColumn(name = "a_id", referencedColumnName = "id"):
    • name = "a_id": 表示在 relation 表中,a_id 列是关联的子 Test 实体(即子节点)的 ID。
    • referencedColumnName = "id": 表示 a_id 列引用的是 Test 实体(test_table)的 id 列。

通过这种方式,我们有效地“翻转”了 joinColumns 和 inverseJoinColumns 的定义,从而能够从同一个 relation 表中以两种不同的视角(获取父或获取子)来解析关系。

完整 Test 实体代码示例

import javax.persistence.*;
import java.util.List;
import java.util.ArrayList; // 建议初始化列表以避免NullPointerException

@Entity
@Table(name = "test_table")
public class Test {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(nullable = false)
    private Long id;

    @Column
    private String comment;

    @ManyToMany(targetEntity = Test.class)
    @JoinTable(
        name = "relation",
        joinColumns = @JoinColumn(name = "a_id", referencedColumnName = "id"),
        inverseJoinColumns = @JoinColumn(name = "a_parent_id", referencedColumnName = "id")
    )
    private List parents = new ArrayList<>(); // 建议初始化

    @ManyToMany(targetEntity = Test.class)
    @JoinTable(
        name

相关专题

更多
hibernate和mybatis有哪些区别
hibernate和mybatis有哪些区别

hibernate和mybatis的区别:1、实现方式;2、性能;3、对象管理的对比;4、缓存机制。本专题为大家提供相关的文章、下载、课程内容,供大家免费下载体验。

141

2024.02.23

Hibernate框架介绍
Hibernate框架介绍

本专题整合了hibernate框架相关内容,阅读专题下面的文章了解更多详细内容。

83

2025.08.06

Java Hibernate框架
Java Hibernate框架

本专题聚焦 Java 主流 ORM 框架 Hibernate 的学习与应用,系统讲解对象关系映射、实体类与表映射、HQL 查询、事务管理、缓存机制与性能优化。通过电商平台、企业管理系统和博客项目等实战案例,帮助学员掌握 Hibernate 在持久层开发中的核心技能。

35

2025.09.02

Hibernate框架搭建
Hibernate框架搭建

本专题整合了Hibernate框架用法,阅读专题下面的文章了解更多详细内容。

64

2025.10.14

class在c语言中的意思
class在c语言中的意思

在C语言中,"class" 是一个关键字,用于定义一个类。想了解更多class的相关内容,可以阅读本专题下面的文章。

468

2024.01.03

python中class的含义
python中class的含义

本专题整合了python中class的相关内容,阅读专题下面的文章了解更多详细内容。

13

2025.12.06

数据库三范式
数据库三范式

数据库三范式是一种设计规范,用于规范化关系型数据库中的数据结构,它通过消除冗余数据、提高数据库性能和数据一致性,提供了一种有效的数据库设计方法。本专题提供数据库三范式相关的文章、下载和课程。

356

2023.06.29

如何删除数据库
如何删除数据库

删除数据库是指在MySQL中完全移除一个数据库及其所包含的所有数据和结构,作用包括:1、释放存储空间;2、确保数据的安全性;3、提高数据库的整体性能,加速查询和操作的执行速度。尽管删除数据库具有一些好处,但在执行任何删除操作之前,务必谨慎操作,并备份重要的数据。删除数据库将永久性地删除所有相关数据和结构,无法回滚。

2077

2023.08.14

c++ 根号
c++ 根号

本专题整合了c++根号相关教程,阅读专题下面的文章了解更多详细内容。

45

2026.01.23

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
Kotlin 教程
Kotlin 教程

共23课时 | 2.8万人学习

C# 教程
C# 教程

共94课时 | 7.5万人学习

Java 教程
Java 教程

共578课时 | 50.8万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号