Engineering Full Stack Apps with Java and JavaScript
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.
We will assume that each course can have many students(one to many), but each student can do only one course(many to one).
We will create two entity classes, Course and Student and do a one to one mapping from course to student, and many to one from student to course.
If you are not following the tutorials in order, refer to the article http://javajee.com/your-first-hibernate-program-using-hibernate-43 for the basic setup including hibernate configuration file.
You should replace the user class in the configuration file with both course and student classes as:
<!-- Names the annotated entity class -->
<mapping class="com.javajee.hiberex.dto.Student"/>
<mapping class="com.javajee.hiberex.dto.Course"/>
Else you will get org.hibernate.MappingException: Unknown entity:…
Basic structure of Student class (without mapping) is:
@Entity
public class Student {
@Id @GeneratedValue
private int studId;
private String studName;
//Getters and setters not shown here; create them manually or generate in eclipse.
}
Basic structure of Course class (without mapping) is:
@Entity
public class Course {
@Id @GeneratedValue
private int courseId;
private String courseName;
//Getters and setters not shown here; create them manually or generate in eclipse.
}
Add a reference to a collection of students from the course and mark the reference variable as @OneToMany.
@Entity
public class Course {
@Id @GeneratedValue
private int courseId;
private String courseName;
@OneToMany
private Collection<Student> studs=new ArrayList<>();
//Getters and setters not shown here; create them manually or generate in eclipse.
}
Test Class
We can use the below test class for testing:
public class CourseTest {
public static void main(String[] args) {
Course course = new Course();
course.setCourseName("C1");
Student stud1 = new Student();
stud1.setStudName("Stud1");
course.getStuds().add(stud1);
Student stud2 = new Student();
stud2.setStudName("Stud2");
course.getStuds().add(stud2);
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new StandardServiceRegistryBuilder().
applySettings(configuration.getProperties()).build();
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(stud1);
session.save(stud2);
session.save(course);
session.getTransaction().commit();
}
}
Queries executed by hibernate during the execution of CourseTest (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 Course_Student (Course_courseId, studs_studId) values (?, ?)
Hibernate: insert into Course_Student (Course_courseId, studs_studId) values (?, ?)
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 {
@Id @GeneratedValue
private int studId;
private String studName;
@ManyToOne
private Course course;
//Getters and setters not shown here; create them manually or generate in eclipse.
}
Test Class
We can use the below modified test class for testing:
public class CourseTest {
public static void main(String[] args) {
Course course = new Course();
course.setCourseName("C1");
Student stud1 = new Student();
stud1.setStudName("Stud1");
stud1.setCourse(course);
course.getStuds().add(stud1);
Student stud2 = new Student();
stud2.setStudName("Stud2");
stud2.setCourse(course);
course.getStuds().add(stud2);
SessionFactory sessionFactory = new Configuration().configure()
.buildSessionFactory();
Session session = sessionFactory.openSession();
session.beginTransaction();
session.save(stud1);
session.save(stud2);
session.save(course);
session.getTransaction().commit();
}
}
Queries executed by hibernate during the execution of CourseTest (as seen in console) is as follows:
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.
In our example, 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.
New Course class is:
@Entity
public class Course {
@Id @GeneratedValue
private int courseId;
private String courseName;
@OneToMany(mappedBy="course")
private Collection<Student> studs=new ArrayList<>();
//Getters and setters not shown here; create them manually or generate in eclipse.
}
If you execute the same test class (as in case 2), queries executed by hibernate during its execution (as seen in console) is as follows:
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=?
As you can see there is no separate mapping table now. Now Student has an additional column course_courseId that refers to the primary key of Course table.