hellzone
hellzone

Reputation: 5236

One to many relationship without reference in Hibernate

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

Answers (2)

WeMakeSoftware
WeMakeSoftware

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

przemek hertel
przemek hertel

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

Related Questions