Spring+PostgreSQL一对多新增子实体出现detached entity错误如何解决?
问题核心原因
你遇到的报错和主键生成失效问题由3个配置和逻辑错误共同导致:
- 级联配置错误:
Reservation类中对Course的关联加了CascadeType.ALL,而Course是预先存入数据库的已有数据,保存Reservation时会触发级联持久化Course,游离态的Course对象就会抛出detached entity passed to persist错误 - 主键类型错误:
Reservation的主键用了基本类型long,默认值为0,Hibernate会判定id为0的实体是已持久化的实体,不会触发主键自动生成逻辑,导致id一直为0 - 冗余的关系维护逻辑:你已经在关系维护端
Reservation设置了appUser属性,无需反向将Reservation加入User的集合再更新User,多余操作会触发级联校验错误
修复步骤
第一步:修改实体类配置
- 修正
Reservation类的Course关联配置,去掉不需要的级联:
// 原配置 @OneToOne(cascade = CascadeType.ALL) @JsonManagedReference private Course course; // 改为,因为Course是独立维护的,不需要Reservation级联操作它 @OneToOne @JsonManagedReference private Course course;
- 修正
Reservation的主键类型为包装类,让Hibernate能识别新实体:
// 原配置 @Id @GeneratedValue(strategy = GenerationType.AUTO) private long id; // 改为 @Id @GeneratedValue(strategy = GenerationType.AUTO) private Long id;
- 可选:初始化AppUser的reservations集合避免空指针:
@OneToMany(mappedBy="appUser", cascade = CascadeType.ALL) private Set<Reservation> reservations = new HashSet<>();
第二步:简化Controller业务逻辑
删除bookCourse方法中冗余的两行代码,关系维护端在Reservation,保存Reservation即可自动关联User和Course:
@RequestMapping(value = "bookCourse/{courseId}") public String bookCourse(@PathVariable("courseId") long id, Principal principal) { AppUser user = appUserService.getAppUser(principal.getName()); Course course = courseService.getCourse(id); Reservation reservation = new Reservation(); reservation.setAppUser(user); reservation.setCourse(course); reservationService.addReservation(reservation); // 删掉下面两行冗余代码即可 // user.getReservations().add(reservation); // appUserService.editAppUser(user); return "redirect:/reservations.html"; }
第三步:清理冗余表
自动生成的appuser_reservation中间表是多余的,一对多关联只需要reservation表的appuser_id外键即可维护,可以直接删除该中间表。
生效验证
修改完成后,新创建的Reservation主键默认值为null,调用save方法时Hibernate会自动触发主键生成策略,Reservation的appuser_id和course_id字段会自动赋值完成关联,不会再出现游离实体报错。
内容的提问来源于stack exchange,提问作者Immo
相关产品推荐
相关产品推荐

