Spring Boot配置orphanRemoval后编辑博客出现Hibernate集合引用丢失错误如何解决
问题原因和修复方案
错误原因
你触发Hibernate异常的核心逻辑如下:
A collection with cascade="all-delete-orphan" was no longer referenced by the owning entity instance
当你给@OneToMany配置了orphanRemoval=true后,Hibernate会严格跟踪Blog实体关联的comments集合的引用,你在编辑博客提交时,Spring MVC直接绑定前端参数生成的新Blog对象的comments集合要么是null,要么是一个全新的List实例,和原来持久化上下文中查出来的Blog对象持有的comments集合不是同一个引用,Hibernate认为你非法替换了要做孤儿删除的关联集合,直接抛出异常。
具体修改方案
1. 调整Blog实体类的comments字段初始化
首先给Blog实体的comments集合初始化一个固定的空集合,避免后续被替换引用,同时避免空指针:
@Entity @Data public class Blog { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Integer id; @ManyToOne private Person person; @OneToMany(mappedBy="blog",cascade=CascadeType.ALL,orphanRemoval=true) private List<Comment> comments = new ArrayList<>(); // 新增初始化代码 }
注意要导入java.util.ArrayList包
2. 修改BlogService的editBlog方法
不要直接用前端绑定的非持久化Blog对象做保存,改成先从数据库查询已有的持久化Blog对象,只更新需要修改的字段,保留原来的comments集合引用:
@Service public class BlogService { // 你原有代码已经注入了BlogRepository,这里无需改动 @Autowired private BlogRepository blogRepository; // 方法新增blogId参数,接收要修改的博客ID public void editBlog(Integer blogId, Blog paramBlog) { // 先从数据库查询持久化状态的Blog对象,其comments集合是Hibernate可识别的合法引用 Blog dbBlog = blogRepository.findById(blogId).orElseThrow(() -> new RuntimeException("对应博客不存在")); // 只赋值需要更新的字段,不要操作comments集合 dbBlog.setTitle(paramBlog.getTitle()); // 请根据你实际的Blog字段补全,比如正文、封面图等 dbBlog.setContent(paramBlog.getContent()); dbBlog.setBase64_str(paramBlog.getBase64_str()); dbBlog.setPostDateTime(LocalDateTime.now() .format(DateTimeFormatter.ofPattern("yyyy/MM/dd HH:mm:ss"))); // 保存持久化对象 blogRepository.save(dbBlog); } public void deleteBlog(Blog blog) { blogRepository.deleteById(blog.getId()); } }
3. 修改PersonController的Post编辑接口
把路径中的blogId传给service层:
@PostMapping("/blog/{blogId}/edit") public String editBlog(@PathVariable("blogId") Integer blogId, @Valid Blog blog,BindingResult bindingResult) { if(bindingResult.hasErrors()) { return"person/create"; } blogService.editBlog(blogId, blog); return"redirect:/person/edit"; }
额外注意事项
- 不要给Blog类的comments字段单独生成setter方法,后续如果需要操作评论集合,只能调用现有comments实例的
add/remove方法,禁止直接使用setComments(new ArrayList<>())替换集合引用 - 原有的删除博客功能无需修改,你配置的级联和孤儿删除规则会自动删除关联的评论,符合需求
内容的提问来源于stack exchange,提问作者chikara
相关产品推荐
相关产品推荐

