Engineering Full Stack Apps with Java and JavaScript
When referencing entities from other entities, we are mapping two entities whereas when referencing a value type we are embedding (or containing) a value type within an entity.
When mapping two entities, we annotate both classes as @Entity, and the mapping type is specified using the annotations @OneToOne, @OneToMany, @ManyToOne or @ManyToMany, over the reference variable declaration of an entity in another entity.
We will consider two entities for mapping examples – a student class and a course class.
This article is a quick reference and does not contain the complete example codes. An example lab with full code will be provided for each of the example code mentioned here.
In One-To-One mapping, we refer to one entity from another and mark the reference variable as @OneToOne.
Join column name can be changed from the default stud_studId using @JoinColumn() annotation
We will assume that there is a one-to-one mapping between a Course and Student – each course can be taken by only one student.
The student class will be a normal entity class annotated with @Entity.
The Course class is similar to the Student class, but will have a reference to the student class annotated as @OneToOne:
@Entity
public class Course {
…
@OneToOne
private Student stud;
…
In test class, save the objects in the below order:
session.save(stud);
session.save(course);
You will see the below queries in console:
Hibernate: insert into Student (studName) values (?)
Hibernate: insert into Course (courseName, stud_studId) values (?, ?)
Change the order of save of student and course as:
session.save(course);
session.save(stud);
You will see the below queries in console:
Hibernate: insert into Course (courseName, stud_studId) values (?, ?)
Hibernate: insert into Student (studName) values (?)
Hibernate: update Course set courseName=?, stud_studId=? where courseId=?
Note: When data is inserted to Course table, studId is not known, but after inserting into Student table, the studId is updated in Course table.
Here the join column name can be changed from the default stud_studId using @JoinColumn() annotation as:
…
@OneToOne
@JoinColumn(name="stud_id")
private Student stud;
…
The complete example for one-to-one mapping is available at http://javajee.com/one-to-one-mapping-in-hibernate-43.
In One-To-Many mapping, we refer to a collection/list of an entity from another entity and mark the reference variable as @OneToMany.
The opposite of this relation from the second entity to the first will be Many-To-One and is annotated as @ManyToOne.
By default during one-to-many and many-to-one, hibernate creates a separate table for mapping details and insert the ids of both the entity tables into it.
In case of one-to-one and many-to-one, you don’t actually require a different mapping table.
You can have a foreign key reference to one of the table id from the other.
We can tell hibernate not to create a separate mapping table, but make use of foreign key reference using the mappedBy parameter of the @One-To-One annotation.
You have to specify the reference variable name for the current entity in the referenced entity.
We have to specify mappedBy for the @OneToMany annotation of Course class and specify the reference variable name used for the Course class in the Student class.
Example (part) for one-to-many
Here, we will assume that each course can have many students(one to many), but each student can do only one course(many to one).
Add a reference to a collection of students from the Course and mark the reference variable as @OneToMany.
@Entity
public class Course {
…
@OneToMany
private Collection<Student> studs=new ArrayList<>();
…
In the test class, when you populate data and save the objects, you can see queries executed by hibernate in the console as:
Hibernate: insert into Student (studName) values (?)
Hibernate: insert into Student (studName) values (?)
Hibernate: insert into Course (courseName) values (?)
Hibernate: insert into Course_Student (Course_courseId, studs_studId) values (?, ?)
Hibernate: insert into Course_Student (Course_courseId, studs_studId) values (?, ?)
Example (part) for many-to-one mapping
Add a reference to the course from the student and mark the reference variable as @ManyToOne in addition to the earlier @OneToMany from course to student.
@Entity
public class Student {
…
@ManyToOne
private Course course;
…
Test class
In the test class, when you populate data and save the objects, you can see queries executed by hibernate in the console as:
Hibernate: insert into Student (course_courseId, studName) values (?, ?)
Hibernate: insert into Student (course_courseId, studName) values (?, ?)
Hibernate: insert into Course (courseName) values (?)
Hibernate: update Student set course_courseId=?, studName=? where studId=?
Hibernate: update Student set course_courseId=?, studName=? where studId=?
Hibernate: insert into Course_Student (Course_courseId, studs_studId) values (?, ?)
Hibernate: insert into Course_Student (Course_courseId, studs_studId) values (?, ?)
We can tell hibernate not to create a separate mapping table, but make use of foreign key reference using the mappedBy parameter of the @One-To-One annotation:
@Entity
public class Course {
…
@OneToMany(mappedBy="course")
private Collection<Student> studs=new ArrayList<>();
…
If you execute the same test class, queries executed by hibernate is:
Hibernate: insert into Student (course_courseId, studName) values (?, ?)
Hibernate: insert into Student (course_courseId, studName) values (?, ?)
Hibernate: insert into Course (courseName) values (?)
Hibernate: update Student set course_courseId=?, studName=? where studId=?
Hibernate: update Student set course_courseId=?, studName=? where studId=?
There is no separate mapping table now. Student table has an additional column course_courseId that refers to the primary key of Course table.
The complete example for one-to-one mapping is available at http://javajee.com/one-to-many-and-many-to-one-mapping-in-hibernate-43.
We should use the annotation @ManyToMany to denote a many to many relationship.
Example scenario: Each course can have many students (many to many), and each student can do many course(many to many).
We will have a collection of Courses in Student, annotated using @ManyToMany:
@Entity
public class Student {
…
@ManyToMany
private Collection<Course> courses=new ArrayList<>();
…
We will have a collection of Student in Course, annotated using @ManyToMany:
@Entity
public class Course {
…
@ManyToMany
private Collection<Student> studs=new ArrayList<>();
…
In the test class, when you populate data and save the objects, you can see queries executed by hibernate in the console as:
Hibernate: insert into Student (studName) values (?)
Hibernate: insert into Student (studName) values (?)
Hibernate: insert into Course (courseName) values (?)
Hibernate: insert into Student_Course (Student_studId, courses_courseId) values (?, ?)
Hibernate: insert into Student_Course (Student_studId, courses_courseId) values (?, ?)
Hibernate: insert into Course_Student (Course_courseId, studs_studId) values (?, ?)
Hibernate: insert into Course_Student (Course_courseId, studs_studId) values (?, ?)
By default, there are two mapping tables in a many-to-one relationship.
This is because when hibernate see one entity class with Many-To-Many mapping, it create a mapping table and when it see the second entity class with Many-To-Many mapping, it again create another mapping table.
Since both mapping table are actually the same, we can tell hibernate not to create two mapping tables, but only one.
You have to use mappedBy attribute with either of the entity tables in a Many-To-Many relationship and specify the reference variable name for the current entity in the referenced entity.
But we should only place the mappedBy for one of them;
if you place mappedBy for both entities, you will get exception: org.hibernate.AnnotationException: Illegal use of mappedBy on both sides of the relationship:…
Example usage
@Entity
public class Course {
…
@ManyToMany(mappedBy="courses")
private Collection<Student> studs=new ArrayList<>();
…
If you execute the same test class, queries executed by hibernate during its execution (as seen in console) is as follows:
Hibernate: insert into Student (studName) values (?)
Hibernate: insert into Student (studName) values (?)
Hibernate: insert into Course (courseName) values (?)
Hibernate: insert into Student_Course (studs_studId, courses_courseId) values (?, ?)
Hibernate: insert into Student_Course (studs_studId, courses_courseId) values (?, ?)
The complete example for one-to-one mapping is available at http://javajee.com/many-to-many-mapping-in-hibernate-43.