JPA实现多对多关系

本文已收录于专栏 《Java》


目录

概念说明

多对多关系是指两个实体之间存在多对多的关联关系。在数据库中,多对多关系无法直接表示,需要通过中间表来实现。

举个例子,假设有两个实体类:学生(Student)和课程(Course)。一个学生可以选择多门课程,而一门课程也可以被多个学生选择。这就是一个多对多的关系。

在数据库中,可以创建三张表来表示多对多关系:学生表(students)、课程表(courses)和中间表(student_course)。中间表中存储了学生和课程之间的关联关系,它包含了学生的ID和课程的ID。

通过中间表,可以将多对多关系拆分为两个一对多关系。学生和课程之间的关系可以被拆分为学生和中间表之间的一对多关系,以及课程和中间表之间的一对多关系。

优势利弊

多对多关系的优点是能够灵活地表示实体之间的复杂关联关系。例如,在上述的学生和课程的例子中,一个学生可以选择多门课程,而一门课程也可以被多个学生选择。这种关系在实际应用中非常常见,通过多对多关系可以方便地表示和操作这种复杂的关联关系。

多对多关系也有一些限制和注意事项。例如,中间表的设计和维护需要一定的注意,以确保关联关系的正确性和一致性。此外,多对多关系可能会导致性能问题,因为查询和操作涉及多个表的关联。因此,在设计和使用多对多关系时,需要仔细考虑和评估实际需求和性能要求。

实现方式

通过两个@ManyToMany注解实现

类图

代码

学生类

java 复制代码
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @ManyToMany
    @JoinTable(name = "student_course",
               joinColumns = @JoinColumn(name = "student_id"),
               inverseJoinColumns = @JoinColumn(name = "course_id"))
    private List<Course> courses;
    
}

在Student实体类中,使用@ManyToMany注解来表示多对多关系,并通过@JoinTable注解指定中间表的名称和关联字段。joinColumns指定了中间表中与Student实体关联的外键字段,inverseJoinColumns指定了中间表中与Course实体关联的外键字段。

课程类

java 复制代码
@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @ManyToMany(mappedBy = "courses")
    private List<Student> students;
    
}

在Course实体类中,使用@ManyToMany(mappedBy = "courses")注解来表示多对多关系,并通过mappedBy属性指定了关联的属性名,即Student实体类中的courses属性。

中间表

通过使用@ManyToMany的方式我们确实可以实现多对多的效果,但是我们没有办法在中间表中添加其他字段,中间表中只有学生的id和课程id。如果我们想要添加一些比如创建时间、更新时间、是否删除的字段是没有办法添加的。如果我们没有需要添加字段的需求那我们直接通过@ManyToMany 的方式即可。如果我们需要添加一些其他的字段就需要调整我们的实现方式。下面我们通过两个@OneToMany和两个@ManyToOne注解来解决这个问题。

通过@OneToMany和@ManyToOne注解实现

类图

代码

学生类

java 复制代码
@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @OneToMany(mappedBy = "student")
    private List<StudentCourse> studentCourses;
    
}

课程类

java 复制代码
@Entity
public class Course {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @OneToMany(mappedBy = "course")
    private List<StudentCourse> studentCourses;
    
}

学生和课程关系类

java 复制代码
@Entity
@Table(name = "student_course")
public class StudentCourse {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    @ManyToOne
    @JoinColumn(name = "student_id")
    private Student student;
    
    @ManyToOne
    @JoinColumn(name = "course_id")
    private Course course;
    
    private int grade;
    
}

这样,通过以上的配置,JPA会自动创建中间表,并维护学生和课程之间的关联关系,同时在中间表中添加了grade字段。你可以通过访问StudentCourse实体类来操作中间表的数据,包括添加学生选课、查询学生所选的课程以及对应的成绩等。

少走弯路

当我们实现了多对多之后我们会发现在具体应用这些对象的时候会出现循环引用的问题,可能会导致堆栈溢出的问题。参考下面博客来解决循环引用带来的问题:

https://blog.csdn.net/weixin_45490198/article/details/131795009

总结提升

  1. 在两个实体类中使用@ManyToMany注解来表示多对多关系,并通过@JoinTable注解指定中间表的名称和关联字段。
  2. JPA会自动创建中间表,并维护两个实体类之间的关联关系。
  3. 如果需要在中间表中添加其他字段,可以创建一个新的实体类来表示中间表,并在两个实体类中使用@OneToMany和@ManyToOne注解来表示与中间表的一对多关系。

🎯 此文章对你有用的话记得留言+点赞+收藏哦🎯

相关推荐
喵手9 分钟前
Python爬虫实战:数据治理实战 - 基于规则与模糊匹配的店铺/公司名实体消歧(附CSV导出 + SQLite持久化存储)!
爬虫·python·数据治理·爬虫实战·零基础python爬虫教学·规则与模糊匹配·店铺公司名实体消岐
喵手10 分钟前
Python爬虫实战:国际电影节入围名单采集与智能分析系统:从数据抓取到获奖预测(附 CSV 导出)!
爬虫·python·爬虫实战·零基础python爬虫教学·采集数据csv导出·采集国际电影节入围名单·从数据抓取到获奖预测
Next_Tech_AI13 分钟前
别用 JS 惯坏了鸿蒙
开发语言·前端·javascript·个人开发·ai编程·harmonyos
chillxiaohan17 分钟前
GO学习记录——多文件调用
开发语言·学习·golang
2301_8223663521 分钟前
C++中的命令模式变体
开发语言·c++·算法
一刻钟.23 分钟前
C#高级语法之线程与任务
开发语言·c#
追逐梦想的张小年38 分钟前
JUC编程03
java·开发语言·idea
派葛穆39 分钟前
Python-PyQt5 安装与配置教程
开发语言·python·qt
万邦科技Lafite1 小时前
一键获取京东商品评论信息,item_reviewAPI接口指南
java·服务器·数据库·开放api·淘宝开放平台·京东开放平台
小乔的编程内容分享站1 小时前
记录使用VSCode调试含scanf()的C语言程序出现的两个问题
c语言·开发语言·笔记·vscode