AndreaNobili AndreaNobili - 7 months ago 15
Java Question

How exactly does the Hibernate @OneToMany annotation work?

I am pretty new to Hibernate and I am studying it on a tutorial. I have some problems understanding how exactly the OneToMany annotation works.

So I have these 2 entity classes: Student that represents a student and Guide that represents a person that guides the student. So each student is associated with a single guide but a single guide can follow more that one student. I want a guide to know the students associated to him.

So I have:

Student:

@Entity
public class Student {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;

@Column(name="enrollment_id", nullable=false)
private String enrollmentId;

private String name;

@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
@JoinColumn(name="guide_id")
private Guide guide;

public Student() {}
public Student(String enrollmentId, String name, Guide guide) {
this.enrollmentId = enrollmentId;
this.name = name;
this.guide = guide;
}

public Guide getGuide() {
return guide;
}
public void setGuide(Guide guide) {
this.guide = guide;
}

}


So the @ManyToOne annotation on the guide field:

@ManyToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
@JoinColumn(name="guide_id")
private Guide guide;


means that a single guide is associated a single student but a guide can follow many students. Is it right? What exactly does the specified cascade settings do? I think it means that when I persist a Student object that contains a Guide object as field also this Guide object is also automatically persisted. And the same thing happens when I remove a Student object, the related Guide record is deleted...but I am not absolutely sure about it...

Ok, doing it this way I will have a mono directional relationship between a record in the Student table and a record in the Guide table because in the Student table I will have a foreign key to join the Guide table so the student can know its guide but, doing it this way, the guide can not know the followed student...and this is not smart.

To do it the Guide class is implemented in this way:

@Entity
public class Guide {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long id;

@Column(name="staff_id", nullable=false)
private String staffId;

private String name;
private Integer salary;

@OneToMany(mappedBy="guide", cascade={CascadeType.PERSIST})
private Set<Student> students = new HashSet<Student>();

public Guide() {}
public Guide(String staffId, String name, Integer salary) {
this.staffId = staffId;
this.name = name;
this.salary = salary;
}

public Set<Student> getStudents() {
return students;
}
public void setSalary(Integer salary) {
this.salary = salary;
}

public void addStudent(Student student) {
students.add(student);
student.setGuide(this);
}

}


So, as you can see, this class contains:

@OneToMany(mappedBy="guide", cascade={CascadeType.PERSIST})
private Set<Student> students = new HashSet<Student>();


that it is used to declare the bidirectional relationship.

So it seems to me that this annotation automatically create a guide_id field into the Student table that represent the foreign key that implement the bidirectional relation.

In fact using this mapping the Student table is automatically created in this way in my database:

'id', 'bigint(20)', 'NO', 'PRI', NULL, 'auto_increment'
'enrollment_id', 'varchar(255)', 'NO', '', NULL, ''
'name', 'varchar(255)', 'YES', '', NULL, ''
'guide_id', 'bigint(20)', 'YES', 'MUL', NULL, ''


So in the Student entity class I have not defined the guide_id field but I have it in the Student table on the database. So I think that the creation of this field in the table depends on the previous @OneToMany annotation defined in the Guide entity class. Is that correct or am I missing something?

Answer

Yes, you can define a @OneToMany entity without a bidirectional association, and the added column is on the Many entity side in the database (even though the entity doesn't know it is linked to the One-side entity).

You can also use a join table for this, but it's not necessary.