本次实验环境:spring boot + spring data jpa + hibernate
本次实验用例:
班级:
id
name
教室:
id
name
一般来说,多对多的关系中,不存在共生的关系。本次试验中,使用班级与教室的关系,大学中,一个班级上不同的课去不同的教室。一个教室可以供多个班级上课。暂且规定班级有课程表标明了上课的教室,但是教室没有课程表,不知道有几个班级会在此上课。
#Grade类:
@Entity
@Table(name="t_n2n_grade")
public class Grade {
@Id
@GeneratedValue
private Long id;
private String name;
@ManyToMany(fetch=FetchType.EAGER, cascade=CascadeType.PERSIST)
@JoinTable(name="t_grade_room", joinColumns= {@JoinColumn(name="grade_id")}, inverseJoinColumns= {@JoinColumn(name="room_id")})
private List<Room> rooms;
//getter与setter省略
}
#Room类:
@Entity
@Table(name="t_n2n_room")
public class Room {
@Id
@GeneratedValue
private Long id;
private String name;
//getter与setter省略
}
#生成表
CRUD:
- 在多对多的关系中,按照实际思维,先有东西,再建立关系。即先创建班级,创建教室,然后关连班级和教室。如果非要在创建班级时就关连一个教室或级联创建教室并关连,也是可以的,cascade可以不写,如果要写只能使用MERGE。
- 添加room,直接添加,或者添加班级时级联添加教室。
Room room = new Room();
room.setName("x7503");
roomDao.saveAndFlush(room);
或
Grade grade = new Grade();
grade.setName("jsj1341");
Room room = new Room();
room.setName("篮球场");
List<Room> list = new ArrayList<>();
list.add(room);
grade.setRooms(list);
gradeDao.saveAndFlush(grade); - 更新room,因为room中不含有grade相关属性,所以可以直接更新,不会影响关系。
Room findOne = roomDao.findOne(1L);
findOne.setName("x9210");
roomDao.saveAndFlush(findOne); 查询room,可以通过id直接查询,也可以查询grade,因为是急加载,会把该班级的所有关连教室都查出来。
Room findOne = roomDao.findOne(1L);
删除room,按照实际情况,删除room之后grade还是存在的,只是两者之间的关连没有了。
因为单向的关系,从room出发无法找到中间表,所以直接删除的时候不能连同中间表中的关连关系一起删掉,会报错。
所以必须先从中间表中删除关系然后再删除room。
Grade grade = gradeDao.findOne(1L);
List<Room> rooms = grade.getRooms();
for(Room temp : rooms) {
if(temp.getId() == 1) {
rooms.remove(temp);
break;
}
}
gradeDao.saveAndFlush(grade);
roomDao.delete(1L);
添加grade,直接添加即可。
Grade grade = new Grade();
grade.setName("jsj1343");
gradeDao.saveAndFlush(grade);更新grade,因为grade中包含room的相关属性,所以更新grade自身的属性,这里是name,必须确保rooms中的数据与数据库中的原数据一致,所以先查询后更新。
Grade findOne = gradeDao.findOne(1L);
findOne.setName("jsj1342");
gradeDao.saveAndFlush(findOne);- 查询grade,直接查询即可,急加载会把相关room的数据一同查出。
- 删除grade,这里得注意一定不能设置级联删除,即CascadeType.REMOVE。
级联删除会把grade,连同中间表和room的对应数据都删掉,首先就不符合逻辑,一个班级毕业删掉了连同教室一起删了,这不正确。正确的状态应该是grade没有了,中间表中的关系没有了,但是教室还在。
如果设置了级联删除,如果其他班级也要使用这个教室,那么删除不成功会报错。
如果没有设置,直接删除即可,grade表与中间表中的数据会正确删除,而room表不会改变。
gradeDao.delete(1L);
- 设置grade与room的关系,实质就是更新grade中的List<Room>类型的变量,注意的要点与更新grade自身属性时一样,没什么好说的。
- 删除grade与room的关系,建议直接写sql去中间表中删除。通过在接口的方法上加上注解@Query(“”, nativeQuery = true)。