持久化含已有关联实体的CourseResult时抛出Detached Entity异常
问题分析:JPA多对多关联持久化时的detached entity异常
我通过CourseResult实体实现Student与Course的多对多关联,相关实体类代码如下:
@Entity(name = "course_result") public class CourseResult { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private BigInteger id; @ManyToOne(targetEntity = Student.class, cascade = CascadeType.ALL) @JoinColumn(name = "student_id") private Student student; @ManyToOne(targetEntity = Course.class, cascade = CascadeType.ALL) @JoinColumn(name = "course_id", referencedColumnName = "id") private Course course; private float grade; }
@Entity public class Course { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private BigInteger id; private String courseName; private String description; @OneToMany(mappedBy = "course", fetch = FetchType.EAGER) private Set<CourseResult> courseResult; }
@Entity public class Student { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private BigInteger id; private String studentName; private String studentClass; @OneToMany(mappedBy = "student", fetch = FetchType.EAGER) private Set<CourseResult> courseResult; }
我设置cascade = CascadeType.ALL,期望持久化CourseResult时,若关联的Course或Student不存在则创建,存在则仅更新。但尝试持久化关联已有Student(ID=1)和Course(ID=1)的新CourseResult时,始终抛出异常,测试代码如下:
Student student = studentRepo.findById(BigInteger.ONE).get(); Course course = courseRepo.findById(BigInteger.ONE).get(); CourseResult courseResult = new CourseResult() .setCourse(course) .setStudent(student) .setGrade(1.5F); courseResultRepository.save(courseResult);
异常信息:
org.springframework.dao.InvalidDataAccessApiUsageException: detached entity passed to persist: org.example.domain.Course; nested exception is org.hibernate.PersistentObjectException: detached entity passed to persist: org.example.domain.Course
原因
问题出在@ManyToOne上配置的cascade = CascadeType.ALL:
CascadeType.ALL包含了PERSIST操作,当你从仓库查询出Student和Course后,这两个实体在查询事务结束后会变成游离态(detached)(即脱离了当前EntityManager的管理)。- 调用
courseResultRepository.save(courseResult)时,JPA会因为级联规则,尝试对关联的游离态Course和Student执行persist操作,但persist方法仅适用于托管态(managed)的新实体(没有ID的实体),不能用于已经拥有ID的游离态实体,因此抛出detached entity passed to persist异常。
解决方案
根据你的需求(关联实体不存在则创建,存在则仅关联),可以选择以下两种方式:
- 调整级联类型
将CascadeType.ALL替换为CascadeType.PERSIST+CascadeType.MERGE,这样既支持创建新的关联实体,也能处理已有实体的关联:
@ManyToOne(targetEntity = Student.class, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "student_id") private Student student; @ManyToOne(targetEntity = Course.class, cascade = {CascadeType.PERSIST, CascadeType.MERGE}) @JoinColumn(name = "course_id", referencedColumnName = "id") private Course course;
- 移除不必要的级联
如果确定关联的Student和Course一定存在,不需要通过CourseResult来创建或更新它们,可以直接去掉级联配置,JPA只会处理CourseResult的持久化:
@ManyToOne(targetEntity = Student.class) @JoinColumn(name = "student_id") private Student student; @ManyToOne(targetEntity = Course.class) @JoinColumn(name = "course_id", referencedColumnName = "id") private Course course;
内容的提问来源于stack exchange,提问作者HieuHT
相关产品推荐
相关产品推荐

