Reputation: 383
I am new to Hibernate and I encountered a problem. I have two entities (Student and Course). Students can have many courses, and courses can have many students. When I am making a new course and add it to the database and in the same session I add this course to the student's courses (student.getCourses().add(course)) everything is working fine and records are added both in the Courses table and the Students_Courses table. When I do the same in the other direction it's not working correctly. First I add a new student in the database. I take an existing course and execute (course.getStudents().add(student)) but no record is saved in the Students_Courses table. Both the many to many mappings are PERSIST cascade, so it has to work.
Do you know what the problem might be? I am using MSSQL database.
First direction (not working - only the new student is saved in the database)
Session session = HibernateUtils.getSessionFactory().openSession();
session.beginTransaction();
{
Faculty faculty = (Faculty) session.get(Faculty.class, 1);
Student newStudent = new Student();
newStudent.setFaculty(faculty);
newStudent.setGrade(3.0);
newStudent.setName("Some student name");
session.save(newStudent);
Course course = (Course) session.get(Course.class, 1);
course.getStudents().add(newStudent);
// session.update(course); This does not have any effect because the course is persistent anyway
session.getTransaction().commit();
session.close();
}
Second direction (working fine - both the new course and the record in the middle table are saved in the database)
Session session = HibernateUtils.getSessionFactory().openSession();
session.beginTransaction();
{
Course newCourse = new Course();
newCourse.setName("Some course name");
session.save(newCourse);
Student student = (Student) session.get(Student.class, 1);
student.getCourses().add(newCourse);
session.getTransaction().commit();
session.close();
}
Here is the Student entity
@Entity(name = "Students")
public class Student {
@Id
@GeneratedValue
@Column(name = "StudentId")
private int id;
@Column(name = "Name", nullable = false, length = 50)
private String name;
@Column(name = "Grade")
private Double grade = null;
@ManyToOne(cascade = CascadeType.PERSIST)
@JoinColumn(name = "FacultyId", nullable = false)
private Faculty faculty;
@ManyToMany(cascade = CascadeType.PERSIST)
@JoinTable(
joinColumns = @JoinColumn(name = "StudentId"),
inverseJoinColumns = @JoinColumn(name = "CourseId"))
private Collection<Course> courses;
public Student() {
this.courses = new HashSet<Course>();
}
// Setters and Getters for all fields
}
And the Course entity
@Entity(name = "Courses")
public class Course {
@Id
@GeneratedValue
@Column(name = "CourseId")
private int id;
@Column(name = "Name", nullable = false, length = 100)
private String name;
@ManyToMany(mappedBy = "courses", cascade = CascadeType.PERSIST)
private Collection<Student> students;
public Course() {
this.students = new HashSet<Student>();
}
// Setters and Getters for all fields
}
Upvotes: 4
Views: 1296
Reputation: 23246
See the following:
Cascade.ALL from non-owning entity side
I would also recommend encapsulating the add/remove operations. Have you getters for these collections return unmodifiable collections and force clients to use the following so the relationships are set correctly:
public class Course{
public void addStudent(Student student){
this.students.add(student);
student.getCourses().add(this);
}
}
public class Student{
public void addCourse(Course course){
this.courses.add(course);
course.students.add(this);
}
}
Upvotes: 1