Reputation: 5236
I have a one to many relationship as you see here. What I want to do is I want to save school object with student objects without setting schools of student objects. Below code works but hibernate inserts null values to school_id_fk column.
public class Student {
....
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "school_id_fk")
private School school;
}
public class School{
....
@OneToMany(cascade = CascadeType.ALL, mappedBy = "school")
private Set<Student> studentSet = new HashSet<Student>(0);
}
and main method;
School school = new School();
school.setSchoolName("school name");
Student student = new Student();
student.setStudentName("studentname1");
student.setStudentSurname("studentsurname1");
//student.setSchool(school); I don't want to set this line
Student student2 = new Student();
student2.setStudentName("studentname2");
student2.setStudentSurname("studentsurname2");
//student2.setSchool(school); I don't want to set this line
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
school.getStudentSet().add(student);
school.getStudentSet().add(student2);
session.save(school);
session.getTransaction().commit();
session.close();
sessionFactory.close();
Upvotes: 0
Views: 112
Reputation: 9162
MappedBy is not needed in school entity
public class School{
....
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "school_id")
private Set<Student> studentSet = new HashSet<Student>(0);
and don't use school in the Student entity
public class Student {
....
}
Upvotes: 1
Reputation: 4004
@Funtik method is correct, however it needs third table.
But your approach is also correct. You can have this relation bidirectional.
If you want to have your school_id_fk
column not null you can use
a common pattern in hibernate with (so called) convenience method:
public class Student {
....
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "school_id_fk")
private School school;
}
public class School{
....
@OneToMany(cascade = CascadeType.ALL, mappedBy = "school")
private Set<Student> studentSet;
// this is private setter (used by hibernate internally)
private void setStudentSet(Set<Student> studentSet) {
this.studentSet = studentSet;
}
// this is public method (exposed API)
public void addStudent(Student) {
if (studentSet == null) {
studentSet = new HashSet<>();
}
student.setSchool(this);
studentSet.add(student);
}
}
As you can see (according to this pattern) you should hide studentSet
as only hibernate should use setStudentSet()
setter.
Private setter will do that. But you can expose public API to operate on this set - addStudent()
in this case.
In addStudent(student)
method student
object is added to set and assigned with parent school in encapsulated way.
Summary: this is common pattern when using hibernate, hide collection setter, expose convenience methods like addStudent()
.
In this approach you have your FK column always filled, and you can fetch School
object from Student
object without HQL query. There is no need for third table in this case.
This is just alternative to @Funtik solution.
Upvotes: 2