@ManyToMany的学习
新建了一个manyToMany的学生-课程表,学生可以选择多个课程,多个课程可以被学生选。尝试如下代码,创建了两个list,然后新建对象,加入list,然后set《list》,报错,这是因为new的新对象
都是暂时的,米有加入。但在这样会生成一个中间表,虽然此时保存了course,中间表需要student,而student是暂时对象,所以报错。
数据库如图:


student中啥也没有。因为没有保存,是暂时对象
错误代码:
student: @ManyToMany
private List<Course> courses;
--------------------------------------
course:
@ManyToMany
private List<Student> students;
----------------------------------
测试代码:
List<Course> courses=new ArrayList<>();
List<Student> students=new ArrayList<>();
------------------------------------------
Student student01=new Student();
student01.setStudentName("student01");
students.add(student01);
Course course01=new Course();
course01.setCourseName("Course01");
courses.add(course01);
student01.setCourses(courses);
course01.setStudents(students);
this.courseDao.save(course01);
this.studentDao.save(student01);
------------------------------------------------------------------------------------------------------------------------------------------------------- 这时候我加入了两个1.mappedBy,用在被维护端,这里的course作为被维护端,student作为维护端,这里只要加了mappedBy的那一端,就意味着放弃了对关系的维护,也不能增删改查中间表的关系。
inverse是控制反转,加了就意味着放弃维护关系的权力。下面是我创建成功的表的截图
在这里用jointable,测试还是上面的方法,没有动,然后就student和course都成功了
这时候你也可以指定在jointable中name指定表名,然后指定外键,joinColumns是主操作表的中间表列,可以有好几个,而inverseJoinColumns是副操作表的中间表列,也就是student作为主操作表,
然后course作为子操作表,我尝试改过@JoinColumn(name="student_ID")变成@JoinColumn(name="student_ID~"),然后中间表就生不成了。 下面是生成上表的代码
course:
@ManyToMany(cascade = CascadeType.REMOVE,fetch = FetchType.EAGER,mappedBy="courses")
private List<Student> students;
student:
@ManyToMany(fetch = FetchType.EAGER,cascade = CascadeType.REMOVE)
@JoinTable(name="students_course"//指定中间的名字是students_course,如果不写也会默认生成,格式是主控方+被控方,或者是joinTable在哪里,就是谁在前
//joinColumns={@JoinColumn(name="student_ID")},//这个是用来指定中间表的主键的,如果不指定,默认为双方表的主键
//inverseJoinColumns={@JoinColumn(name="course_ID")}//这个是用来指定中间表的放弃控制的表的,inverse嘛,就是控制反转,放弃控制权限。因为这里已经用了mappedBy,已经放弃了
)
下面的代码是用来测试被放弃的一端能不能操纵数据库的片段代码,发现并不能删除中间表的关系
test:
Course course01=this.courseDao.findByCourse_name("Course01");
List<Student> students=course01.getStudents();
for (int i=0;i<students.size();i++){
if (students.get(i).getStudentName().equals("student02")){
students.remove(students.get(i));
course01.setStudents(students);
this.courseDao.save(course01);
System.out.println("删除关系成功");
}else {
System.out.println("不存在关系");
}
}
上面是指定了student作为主控方的,我们来测试一下,下面是测试代码和测试结果,中间表中的一个关系被删除了
操作方法是,先找到这个学生,然后得到他的选课list,然后move掉list中的某个,再进行保存
Student student01=this.studentDao.findByStudent_name("student01");
List<Course> courses=student01.getCourses();
for (int i=0;i<courses.size();i++){
if(courses.get(i).getCourseName().equals("course02")){
courses.remove(courses.get(i));
student01.setCourses(courses);
this.studentDao.save(student01);
System.out.println("删除关系成功");
}else {
System.out.println("不存在关系");
}
}

-----------------------------
student:
@ManyToMany()
@JoinTable()//创建了中间表
private List<Course> courses;
-----------------------------
course:
@ManyToMany(mappedBy = "courses")//被维护端
--------------------------------------------------------------------------------------------------------------------------------------------------------
在之后我在测试中,注释了student的保存的save方法,留着course的save,于是可以运行成功,course保存,然后student还是空表,当然student-cours也是空表,数据库的默认中间表是这样的,
谁作为维护,谁在前,比如这里的中间表是student。
this.courseDao.save(course01);
this.courseDao.save(course02);
// this.studentDao.save(student01);
// this.studentDao.save(student02);
-------------------------------------------------------------------------------------------------------------------------------------------------------
然后就是增删改查的操作了,findByStudent_name是我自己写的一个@Query函数,可以用id查。emm~写个删吧,
这是删中间表的关系,注意这里要设置成@ManyToMany(fetch = FetchType.EAGER),不然会爆出
session错误。因为这个已经跨表了 1.这个是删除对象,
2.删除被控方course:因为我上面设计的时候设计了级联,student和course都设置了REMOVE。额,,,我也不知我为什么设置,你删我,我删你,按照下面的代码做下去的时候,就全部删除了。course和student,
中间表都删除空了...
Course course01=this.courseDao.findByCourse_name("Course01");
this.courseDao.delete(course01);
System.out.println("删除course01成功");
3.在我把级联去掉后,我试着删除了student01,发现student中的student01被删除,然后中间表中的关系被删除,
// Student studen01=this.studentDao.findByStudent_name("student01");
// this.studentDao.delete(studen01);
// System.out.println("删除student01成功");
4.我在尝试一下删除course,发现可以删除成功,但是中间表没有进行更新修改,这就出问题了,课都没了,学生还在选,那可不行
Course course01=this.courseDao.findByCourse_name("Course01");
this.courseDao.delete(course01);
System.out.println("删除course01成功");
--------------------------------
// Course course01=this.courseDao.findByCourse_name("Course01");//这段代码是错误的,因为course已经设置为被维护端,不会维护,所以在操纵数据库的时候就只会
//进行查询,而不能进行修改。
// List<Student> students=course01.getStudents();
// for (int i=0;i<students.size();i++){
// if (students.get(i).getStudentName().equals("student02")){
// students.remove(students.get(i));
// course01.setStudents(students);
// this.courseDao.save(course01);
// System.out.println("删除关系成功");
// }else {
// System.out.println("不存在关系");
// }
// }
Student student01=this.studentDao.findByStudent_name("student01");//这段代码是正确的,因为students是维护方,如果进行删除操作,就会出现查询,删除操作,和保存。
List<Course> courses=student01.getCourses();
for (int i=0;i<courses.size();i++){
if(courses.get(i).getCourseName().equals("Course01")){
courses.remove(courses.get(i));
student01.setCourses(courses);
this.studentDao.save(student01);
System.out.println("删除关系成功");
}else {
System.out.println("不存在关系");
}
}
-------------------------------------------------------------------------------------------------------------------------------------------------------
-------------------------------------------------------------------------------------------------------------------------------------------------------
多对多的关系是靠第三表来维护的,所以不建议执行级联删除操作,可以直接修改第三表实现,比如student和course,
如果出现学生不选这门课程了,或者学生修改了其他的,是对中间表的操作,比如这里有俩学生,俩课程。如果是全选,也就是
2*2=4,中间表中有四条记录,那么修改的时候就只需要增删改查中间表就可以修改学生对应的选课。下面有个增的例子
增------------------------
List<Student> students=new ArrayList<>();
Student student01=new Student();
student01.setStudentName("student01");
students.add(student01);
Course course01=this.courseDao.findByCourse_name("Course01");
List<Course> courses=new ArrayList<>();
courses.add(course01);
course01.setStudents(students);
student01.setCourses(courses);
this.courseDao.save(course01);
this.studentDao.save(student01);
System.out.println("HHHHHHHHHH新建成功");
-------------------------------------------------------------------------------------------------------------------------------------------------------
如果不喜欢这个,可以进行级联保存,
放弃外键维护权:比如student和course,如果course放弃外键维护权,即不维护外键,也就是如果设置了student上设置级联保存,那么在新建student并且new了course放置在student里,进行
这时候保存student,student和course都会被保存,但这时course里的外键会是空。
(来源)https://blog.csdn.net/jjizh/article/details/76449334
-------------------------------------------------------------------------------------------------------------------------------------------------------
@JoinTable参数详解:
(来源)https://blog.csdn.net/jiangyu1013/article/details/79503581
@ManyToMany的学习的更多相关文章
- 码农小汪-Hibernate学习8-hibernate关联关系注解表示@OneToMany mappedBy @ManyToMany @JoinTable
近期我也是有点郁闷,究竟是程序中处理关联关系.还是直接使用外键处理关联关系呢?这个的说法不一致!程序中处理这样的关联关系的话.自己去维护这样的约束.这样的非常乐观的一种做法!或者是直接在数据库中处理这 ...
- 【Python学习笔记】Coursera课程《Using Databases with Python》 密歇根大学 Charles Severance——Week4 Many-to-Many Relationships in SQL课堂笔记
Coursera课程<Using Databases with Python> 密歇根大学 Week4 Many-to-Many Relationships in SQL 15.8 Man ...
- 《Django By Example》第二章 中文 翻译 (个人学习,渣翻)
书籍出处:https://www.packtpub.com/web-development/django-example 原作者:Antonio Melé (译者注:翻译完第一章后,发现翻译第二章的速 ...
- EF Code First学习系列
EF Model First在实际工作中基本用不到,前段时间学了一下,大概的了解一下.现在开始学习Code First这种方式.这也是在实际工作中用到最多的方式. 下面先给出一些目录: 1.什么是Co ...
- EF(Entity Framework)系统学习系列
好久没写博客了,继续开启霸屏模式,好了,废话不多说,这次准备重新系统学一下EF,一个偶然的机会找到了一个学习EF的网站(http://www.entityframeworktutorial.net/) ...
- SSH学习笔记
Struts2登录模块处理流程: 浏览器发送请求http://localhost/appname/login.action,到web应用服务器: 容器接收到该请求,根据web.xml的配置,服务器将请 ...
- 11.Configure Many-to-Many(配置多对多关系)【Code-First系列】
现在学习EF Code-First多对多的配置. 这里我们举例:学生和班级实体,一个学生可以选修多个课程,多个学生也可以选修同一个课程. 一.使用数据注解特性,配置多对多的关系 using Syste ...
- Hibernate学习笔记(二)
2016/4/22 23:19:44 Hibernate学习笔记(二) 1.1 Hibernate的持久化类状态 1.1.1 Hibernate的持久化类状态 持久化:就是一个实体类与数据库表建立了映 ...
- Python学习路程day18
Python之路,Day18 - Django适当进阶篇 本节内容 学员管理系统练习 Django ORM操作进阶 用户认证 Django练习小项目:学员管理系统设计开发 带着项目需求学习是最有趣和效 ...
随机推荐
- asp.net mvc5中使用Swagger 自动生成WebApi文档笔记
Swagger可以自动生成Api说明文档,并内置在线测试,通过NSwagStudio还可以自动生成Api客户端调用代码,以下为具体实现步骤 1.写一个简单的WebApi并加上注释 public cla ...
- Centos 7.5下搭建SVN源代码服务器
1.先查看是否存在svn,没有就需要安装svn svnserve --version #查看svn版本号 which svn #查看svn程序所在目录 yum install subversion - ...
- java 导出 excel 最佳实践,java 大文件 excel 避免OOM(内存溢出) excel 工具框架
产品需求 产品经理需要导出一个页面的所有的信息到 EXCEL 文件. 需求分析 对于 excel 导出,是一个很常见的需求. 最常见的解决方案就是使用 poi 直接同步导出一个 excel 文件. 客 ...
- H3路由器映射端口到外网
登录华三路由器 依次点击菜单 “防火墙”-->“NAT”-->“内部服务器” 将看到一个内部服务器转换的列表页面 点击列表页面的的新建然后完善页面提交即可 如下操作:
- bochs的bochsrc说明
########################################## Configuration file for bochs ################### ...
- join,left join,inner join,full join的区别?
left join(左联接) 返回包括左表中的所有记录和右表中联结字段相等的记录 right join(右联接) 返回包括右表中的所有记录和左表中联结字段相等的记录inner join(等值连接) 只 ...
- (转)Android 只开启一个Activity实例
在一个Activity中,多次调用startActivity()来启动另一个Activity,要想只生成一个Activity实例,方法有两种. 方法一:设置起动模式 一个Activity有四种启动模式 ...
- MM-分割评估
SAP MM分割评估 https://blog.csdn.net/kangliujie/article/details/76681333 SAP MM批次管理分割评估 https://blog.csd ...
- mac安装linux双系统的吐槽
[First day] 尝试安装mac - linux 双系统 首先,尝试的是ubuntu16.06版本,要把双系统安装至电脑硬盘512G SSD中, *** 分盘 1.1 打开实用工具中的磁盘管理工 ...
- Jmeter生成html报告
进入到jmeter安全目录bin下,执行以下命令 基本命令格式: jmeter -n -t test.jmx(性能测试脚本) -l testResult.csv(测试监听结果文件) -e -o tes ...




