I'm trying to map 2 entities (Course and Student), I have 2 Java classes and 2 MySQL tables, having a ManyToMany
relationship. I created the junction table and java class Enrolment (as I want extra information such as the date of enrolment of a student to a course).
I'm trying to insert data using hibernate in this Enrolments table in the MySQL but I keep getting errors. Here are my POJO classes:
Course class:
@Entity
@Table(name = "course")
public class Course {
private int id;
@Column(name = "chapter_id")
private int chapterId;;
@Column(name = "name")
private String title;
@Column(name = "teacher_user_id")
private int teacherId;
@OneToMany(targetEntity=Enrolment.class, mappedBy="course", fetch=FetchType.LAZY)
// @JoinTable(name = "enrolment",
// joinColumns = @JoinColumn(name = "course_id"),
// inverseJoinColumns = @JoinColumn(name = "student_user_id"))
private List<Enrolment> enrolments = new ArrayList<Enrolment>();
public Course(){}
public Course(int id, int chapterId, String title, int teacherId) {
super();
this.id = id;
this.chapterId = chapterId;
this.title = title;
this.teacherId = teacherId;
}
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public int getChapterId() {
return chapterId;
}
public void setChapterId(int chapterId) {
this.chapterId = chapterId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public int getTeacherId() {
return teacherId;
}
public void setTeacherId(int teacherId) {
this.teacherId = teacherId;
}
@OneToMany(mappedBy = "course")
public List<Enrolment> getEnrolments() {
return enrolments;
}
public void setEnrolments(List<Enrolment> courses) {
this.enrolments = courses;
}
public void addEnrolment(Enrolment enrolment) {
this.enrolments.add(enrolment);
}
}
Student class (this class is inherited from User parent class, I will attach User Class down below as well. In the database there are different tables as well: User and then Student and Teacher that inherit User parent entity):
@Entity
@Table(name = "student")
@PrimaryKeyJoinColumn(name = "user_id")
@OnDelete(action = OnDeleteAction.CASCADE)
public class Student extends User {
private int grade;
private List<Enrolment> enrolments = new ArrayList<Enrolment>();
public Student(){}
public Student(String fname, String lname, String email, String password, String address, String phone,
int userType, int grade, boolean isAdmin)
{
super(fname, lname, email, password, address, phone, userType, isAdmin);
this.grade=grade;
}
public int getGrade() {
return grade;
}
public void setGrade(int grade) {
this.grade = grade;
}
public void setEnrolments(List<Enrolment> courses) {
this.enrolments = courses;
}
@OneToMany(mappedBy = "student")
public List<Enrolment> getEnrolments() {
return enrolments;
}
public void addCourse(Enrolment course) {
this.enrolments.add(course);
}
public void addEnrolment(Enrolment enrolment) {
this.enrolments.add(enrolment);
}
}
User Class:
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@Table(name = "user")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String firstname;
private String lastname;
private String email;
private String password;
private String address;
private String phone;
@Column(name = "user_type_id")
private int userType;
@Column(name = "is_admin")
private boolean isAdmin;
public User(String fname, String lname, String email, String password, String address, String phone,
int userType, boolean isAdmin) {
//super();
this.firstname = fname;
this.lastname = lname;
this.email = email;
this.password = password;
this.address = address;
this.phone = phone;
this.userType = userType;
this.isAdmin = isAdmin;
}
public User() {}
//getters & setters
And finally this is the Enrolment class:
@Entity
@Table(name = "enrolment")
public class Enrolment {
private int id;
private Student user;
private Course course;
@Column(name = "enrolment_date")
private Date enrolmentDate;
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "student_user_id")
public User getUser() {
return user;
}
public void setUser(Student user) {
this.user = user;
}
@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name = "course_id")
public Course getCourse() {
return course;
}
public void setCourse(Course course) {
this.course = course;
}
public Date getEnrolmentDate() {
return enrolmentDate;
}
public void setEnrolmentDate(Date enrolmentDate) {
this.enrolmentDate = enrolmentDate;
}
So I'm trying to read a course and a student from database and insert the information in this Enrolment table but it gives errors since trying to read a Course. Here is the DAO method:
@SuppressWarnings("deprecation")
@Transactional
public List<Course> getCoursesOfChapter(int chapterId) {
Configuration con = new Configuration().configure("hibernate.cfg.xml").addAnnotatedClass(Course.class);
SessionFactory sf = con.buildSessionFactory();
Session session = sf.openSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("from Course where chapter_id = :chapterId");
query.setParameter("chapterId",chapterId);
// List list = query.list();
tx.commit();
return (List<Course>) query.list();
It throws the error at the session factory building:
Exception in thread "main" org.hibernate.AnnotationException: Use of @OneToMany or @ManyToMany targeting an unmapped class: models.Course.enrolments[models.Enrolment]
at org.hibernate.cfg.annotations.CollectionBinder.bindManyToManySecondPass(CollectionBinder.java:1255)
at org.hibernate.cfg.annotations.CollectionBinder.bindStarToManySecondPass(CollectionBinder.java:808)
at org.hibernate.cfg.annotations.CollectionBinder$1.secondPass(CollectionBinder.java:733)
at org.hibernate.cfg.CollectionSecondPass.doSecondPass(CollectionSecondPass.java:54)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1696)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1664)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:287)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:84)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:474)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:689)
at dao.CourseDAO.getCourse(CourseDAO.java:52)
at webapp.Main.main(Main.java:132)
Finally, this is my call:
CourseDAO cdao = new CourseDAO();
Course course = cdao.getCourse(1);
I've tried playing with the annotations, make them ManyToMany instead of ManyToOne. I tried to map the User class instead of Student but still didn't work. I tried to make it without the junction class of Enrolment and just generate it without having an actual class for it but still didn't work (as I had to work with 2 session.save() methods one after the other which also gave some error that I couldn't solve). Probably it's a small thing that I'm missing here but I just can't figure it out, sorry for too long code but I really need to solve it fast. If you read through here, I really thank you!
So my question is: Am I missing something here from these mappings and annotations or I should change the structure of my classes?