Engineering Full Stack Apps with Java and JavaScript
An entity class in hibernate can refer to other entity classes or embed value types. An entity is a type on its own and has an existence of its own like a Course and its students. A value type is a type which doesn't have existence of its own, but belongs to an entity like a user and his address. Value types are always completely owned by their containing entity. Once you delete the entity, its associated value types are also deleted. But when you delete an entity, referenced entities still exist: when you delete a Course entity, you don't delete all its students. When referencing entities, we are actually mapping two entities whereas when referencing a value type we are embedding (or containing) a value type within an entity. When embedding a value type, we annotate the embedded class as @Embedding and the declaration of it within the embedding class as @Embedded. When mapping two entities, we annotate both classes as @Entity and the mapping type is specified over the declaration of an entity in another entity as @OneToOne, @OneToMany, @ManyToOne or @ManyToMany.
We have already seen the details of embedding value type (address class) in an entity (user class). Here we will see details of mapping of two entity classes with examples. 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, but only the most important part of the code. Each mapping heading will contain a link to the complete example with detailed how-to-do steps and full code.
One-To-One mapping
In One-To-One mapping, we refer to one entity from another and mark the reference variable as @OneToOne. In One-To-One mapping, 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:
@Entity
public class Student {
…
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;
…
You also need a test class, where you populate data by calling the getters and setters of both Course and Student; and then save the objects.
If you 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 (?, ?)
If you 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=?
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.
One-to-Many and Many-to-One Mapping
In One-To-Many mapping, we refer to a collection/list of the 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. The example will make things more clear. 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).
Just to test one-to-many, 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 (?, ?)
To test, Many-To-One with One-To-Many, 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;
…
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 (?, ?)
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, which is course:
@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-hibernate4.
Many-To-Many mapping
In Many-To-Many mapping, we refer to a collection/list of the entity from another entity and vice versa; and used @ManyToOne annotation on declarations of both entity collections. Here, we will assume that each course can have many students (many to many), and each student can do many course(many to many). We will create two entity classes, Course and Student and do a many to many mapping from course to student, and again many to many mapping from student to course.
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 (?, ?)
Many-To-Many with mappedBy
In case of Many-To-One mapping, we cannot eliminate the mapping table; however in the above output there are two mapping tables. This is because when hibernate see one entity class with Many-To-One mapping, it create a mapping table and when it see the second entity class with Many-To-One 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:… We have to specify mappedBy for the @ManyToMany annotation of Course class and specify the reference variable name used for the Course class in the Student class, which is course.
@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.