I am new to hibernate, and today I found something weird about CascadeType in one_to_many mode.
case 1: CascadeType.ALL In this case everything works fine. When an object is saved, all related objects are saved too(as expected from cascade). For example when a Course object is created and assigned an Instructor object, saving the Course object means both are saved.
case 2: Explicitly typing all options
@ManyToOne(cascade = {CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.PERSIST,
CascadeType.REFRESH,
CascadeType.REMOVE})
In this case, although every possible options are mentioned an exception is thrown and says:
TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing
I wonder what the difference is.
This has happened on the hibernate 5.4.3.
import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;
@Entity
@Table(name = "course")
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "title")
private String title;
// @ManyToOne(cascade = CascadeType.ALL)
@ManyToOne(cascade = {CascadeType.DETACH,
CascadeType.MERGE,
CascadeType.PERSIST,
CascadeType.REFRESH,
CascadeType.REMOVE})
@JoinColumn(name = "instructor_id")
private Instructor instructor;
public Course(String title) {
this.title = title;
}
public Course() {
}
public Instructor getInstructor() {
return instructor;
}
public void setInstructor(Instructor instructor) {
this.instructor = instructor;
}
}
@Entity
@Table(name = "instructor")
public class Instructor {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private int id;
@Column(name = "first_name")
private String firstName;
@Column(name = "last_name")
private String lastName;
@Column(name = "email")
private String email;
@OneToMany(mappedBy = "instructor", cascade = CascadeType.ALL)
private List<Course> courses;
public Instructor(String firstName, String lastName, String email){
this.firstName = firstName;
this.lastName = lastName;
this.email = email;
}
public Instructor() {
}
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
public void add(Course tempCourse){
if (courses==null){
courses = new ArrayList<>();
}
courses.add(tempCourse);
tempCourse.setInstructor(this);
}
}
Always remember when you use cascade type ALL, it not only includes all the explicit cascading events (persist, detach, remove..etc), but also includes some hibernate native cascade types(Lock). This error is also telling the same story. It enforce to the hibernate save all child object before saving the parent object.
in one short Cascade.ALL !={CascadeType.DETACH, CascadeType.MERGE, CascadeType.PERSIST,CascadeType.REFRESH}
This is more than that....:)
Please go through below article, you would understand