My example below is for learning purpose. The goal is to create some examples using the Composite identifiers. Unfortunately, I'm getting some strange results.
Entities: Course, Teacher, CoursePk.
Each course should be given by only one Teacher.
I'm using a bidirectional relation @OneToOne() between the class Teacher and the class Course.
Each Course contains a composite primary key. In my example I'm simplifying and I'm using a composite primary key that use only one attribute.
The goal of my example is to persist the associated teacher when the course object is persisted.
The Teacher Class:
@Entity(name = "Teacher")
public class Teacher {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
@Column(name = "firstName")
private String firstName;
@Column(name = "lastName")
private String lastName;
@OneToOne(mappedBy = "officialTeacher")
private Course course;
//setter getter constructors are omitted for brevity
}
The Course class:
@Entity(name = "Course")
public class Course {
@EmbeddedId
private CoursePk pkCourse;
@OneToOne(cascade = CascadeType.PERSIST)
private Teacher officialTeacher;
//setter getter constructors are omitted for brevity
}
The CoursePk that should represents a composite primary key.
@Embeddable
public class CoursePk implements Serializable {
@Column(name = "courseName")
private Integer courseId;
}
My running example:
private void composedPrimaryKey() {
Teacher teacher = new Teacher("Jeff", "Boss");
CoursePk composedPK = new CoursePk(1);
Course course = new Course(composedPK, teacher);
Course savedCourse = courseRepository.save(course);
}
With that my tables looks like:
course table
course_name | official_teacher_id
1 | 1
teacher table
id | first_name |last_name
1 | null | null
As you can see, the information of the teacher are not persisted, but only the id field.
Magically when I change the cascade type to CascadeType.ALL, everything is persisted.
id | first_name |last_name
1 | Jeff | Boss
Could someone explains why it didn't works with only CascadeType.PERSIST.
Spring Data JPA:
CrudRepository.save(…)method behaviourGiven that Spring Data JPA is used, there is some specifics on how the
CrudRepository.save(…)method detects the method call to be performed: eitherEntityManager.persist(…)orEntityManager.merge(…):Back to the question
Coming back to the piece of code mentioned in the question.
Since the identifier property (the primary key) of the
Courseinstance is not null, Spring Data JPA considers it as an existing (not new) entity and calls theEntityManager.merge(…)method instead of theEntityManager.persist(…)method.Additional references
Additionally, please, refer to the related question: java - JPA CascadeType Persist doesn't work with spring data.