Most webapps aim at slapping an UI to a back-end relational db.  A well-designed and normalized relational db (and YES, with surrogate keys!) is therefore extremely important and will void 99.9% of the problems at start and in the long-term/life maintenance of a web application.  ORM using JPA is the way Java developers create objects(POJOs)  for use in all the 3 layers of a webapp(of course!, I am assuming the app would have a presentation, service and a dao layer – after all, if you have the 3 layers to start with, slapping different UIs, be it for mobile or for the web or for the desktop,  would be very easy.  And if you expose  the needed services in the service layer as web services,  you get the most bang for the buck…any language front-end is possible)

ORM with JPA is all good, but sometimes the ORM tools generate odd code and as a Java developer you should have the knowledge to correct if there are any anomalies with the relations within auto-generated code. Hope this post helps you understand the innards of  relations within the ORM-generated JPA code.

For this post let me define the CROW (Course Registration Over the Web) db: It has five main tables: Course, Department, Professor,  Student, PC with relations like so: a 1-to-1  relation between Student and PC,  a 1-to-many relation between Department and Professor,  a many-to-1 relation between Professor and Department,  a many-to-many relation between Student and Course.

Relationships can be further classified into Single-Valued associations and Collection-valued associations.

Single-valued associations would be 1-to-1 and many-to-1:  Here the most important JPA annotation you will see is the @JoinColumn, which would refer to the relevant foreign key for the table mapped.  So, for example “PC_ID” is the foreign key in Student table and it would be referred within the @JoinColumn annotation placed over the “pc” field. PC_ID will be the PK for PC table.  The owning side of a relationship is the one that has the @JoinColumn annotation(also simply, the side that contains the FK in the relationship). The inverse side is the other side of the relation(the one without the FK)

1-to-1 :

Uni-directional:

@Entity
public class Student {
@Id
private int id;
private String firstName;
@OneToOne
@JoinColumn(name=”PC_ID”)
private PC pc;
// …
}

Bi-directional: note the “mappedBy” in code snippet. “mappedBy” is always used on the inverse side (or the side without the FK in the relationship) and tells us what the name of the field is called in the owning side of the relationship.

@Entity
public class PC {
@Id
private int id;
private String brandName;
@OneToOne(mappedBy=”pc”)
private Student student;
// …
}

Many-to-1 :

@Entity
public class Professor {
@Id
private int id;
@ManyToOne
@JoinColumn(name=”DEPT_ID”)
private Department department;
// …
}

Collection-valued associations would be 1-to-many and many-to-many

1-to-Many:

If Department referred back to Professor, it would be a bi-directional relationship. One department would thus have a collection of professors. So 1-to-Many in effect would be a Many-to-1 bidirectional relationship from Professor to Department with the owning side being the Professor and the inverse being the Department.  So the Professor mapping would be as before like in Many-to-1, but the Department mapping would change like so.  Department is the inverse side of the relation as it does not refer to a FK and would contain the “mappedBy”.

@Entity
public class Department {
@Id private int id;
private String name;
@OneToMany(mappedBy=”department”)
private Collection<Professor> professors;
// …
}

Many-to-Many :

There is always a join table connecting the two tables. Here I have picked Student as the owning side of the relationship(it is up to you). There is no one join column and hence. But it is a must to pick one as the owner and the other as the inverse. Also the owning side(again your choice) would have the@JoinTable annotation.

@Entity
public class Student {
@Id
private int id;
private String firstName;
@ManyToMany
@JoinTable(name=”STUDENT_COURSE,
joinColumns=@JoinColumn(name=”STUDENT_ID”),          inverseJoinColumns=@JoinColumn(name=”COURSE_ID”))
private Collection<Course> courses;
// …
}

@Entity
public class Course{
@Id private int id;
private String courseName;
@ManyToMany(mappedBy=”courses”)
private Collection<Student> students;
// …
}

[Note: the above only works if you don't have  fields other than STUDENT_ID and COURSE_ID  in the join table STUDENT_COURSE.  Means, if you have other fields within the tables, then you would be forced to map STUDENT_COURSE also into an entity with STUDENT and COURSE each having a 1-to-Many relationship with the STUDENT_COURSE table.]

Advertisement