Hibernate Made Easy
Simplified Data Persistence with Hibernate & JPA Annotations
Suggested Retail Price:   $54.98
Current Amazon Purchase Price:   $54.98
When you buy through us on Amazon:   $45.98
You won't find a better price!
Buy through us...Help support the site.
Most Popular Videos
'Cuz some people don't like reading...
Hibernate JPA Video CBT Tutorials Setting up the environment  Setting Up Hibernate
Hibernate and RSA IRAD Rational Software Architect Application Developer CBT Tutorial  Hibernate & Rational (IRAD)
Hibernate JPA Training  Many to Many Associations
Java Persistence With Hibernate Tutorials  Inheritance Mapping
Working with Compund Primary Keys  Compound Primary Keys
Hibernate and Eclipse Tools CBT Tutorial  Using Hibernate & Eclipse
Portlet Programming
Do you Portal? Then you need this...
WebSphere: What is WebSphere? Java J2EE JEE Portal and Beyond

I Even Made Portlets Real Easy :)
Please Spread the Word!
Why keep HiberBook a secret???







If you found this site helpful, please tell other people about it. I'd really, really appreciate it.

SCJA Java Study Guide
Written with your success in mind...
WebSphere: What is WebSphere? Java J2EE JEE Portal and Beyond

Get Java Certified by Sun
Is Google Clairvoyant?
Google thinks you'll like this...
What is WebSphere?
I wrote this... I know you'll love it...
WebSphere: What is WebSphere? Java J2EE JEE Portal and Beyond

Buy it now!
Most Popular Purchases
What people are buying from us...
Popular Hibernate Purchases  Hibernate Made Easy
Popular Hibernate JPA Books  Harnessing Hibernate
The Best Spring and Hibernate Books  Java Persistence w Hibernate
Java Persistence API Books  Spring in Action
Popular Spring and JBoss Books  What is WebSphere?
Popular Spring and JBoss Books  JSR168 Portlet Programming
The SCJA Exam Questions
I wrote this, too. A Great Exam Prep...
WebSphere: What is WebSphere? Java J2EE JEE Portal and Beyond

Get Sun Java Certified
Most Popular Tutorials
High hit reads on this site...
Hibernate and JPA Links  How Hibernate Works
Hibernate and JPA Free Tutorials  Recommended Books
Hibernate and JPA Simple Examples  Coding Advanced DAOs
Hibernate and JPA Free CBTs  Using The Criteria API
Hibernate and JPA Simple Examples  What is Hibernate?
down caret hibernate jpaAre you Harnessing It?
One of the three books you need...
Harnessing Hibernate Book by James Elliott (Author), Tim O'Brien (Author), Ryan Fowler (Author)
Read My Review
Win Yourself $100!!!
The 100% Error Free Code Challenge...

The $100 Code Challenge - No Code Errors, Guaranteed!!!
Learn How to Win a Benjamin

HardCore Hibernate
Yeah, you need this book, too...
Hibernate and JPA Simple Examples

If my book makes it Easy, this book makes Hibernate Hardcore. This is the reference standard...You need it.

Read My Review
Friendly Links
Websites we like...
Hibernate and JPA Links  JavaRanch: Big Moose Saloon
Hibernate and JPA Free Tutorials  Apache.org
Hibernate and JPA Free CBTs  Pickering is Springfield
Hibernate and JPA Simple Examples  Hibernate.org
Hibernate and JPA Simple Examples  mysql.org
Hibernate and JPA Simple Examples  Coast to Coast
Hibernate and JPA Simple Examples  What is IBM WebSphere?
Hibernate and JPA Simple Examples  Desktop Tower Defense
Is Amazon Psychic?
Amazon thinks you'll like this...

My Other Books & Stuff
Other decent books of mine :)...
Sun Certified Java Associate SCJA Study Guide  Java Associate Study Guide
SCJA Mock Exam Questions  SCJA Questions Guide
JSR-168 Portlet Development Book  JSR168 Portlet Programming
WebSphere Introduction and Support Book  What is WebSphere?
The Simpsons is based on Pickering Ontario  Pickering is Springfield
Oshawa Ontario, Discerning Bombs A book about like in Oshawa Ontario  Discerning Bombs on Oshawa
A Good Book on Hibernate and JPA the Java Persistence API  Hibernate Made Easy
From Amazon with Love
Check this stuff out...
Please Spread the Word!
Why keep HiberBook a secret???







If you found this site helpful, please tell other people about it. I'd really, really appreciate it.

More Google Stuff...
Links to entertain you...
Most Popular Purchases
What people are buying from us...
Popular Hibernate Purchases  Hibernate Made Easy
Popular Hibernate JPA Books  Harnessing Hibernate
The Best Spring and Hibernate Books  Java Persistence w Hibernate
Java Persistence API Books  Spring in Action
Popular Spring and JBoss Books  What is WebSphere?
Popular Spring and JBoss Books  JSR168 Portlet Programming
Mapping Many-to-Many Relationships with Hibernate and JPA Annotations
A simple tutorial explaining how to map a many 2 many relationship between classes...


Of all of the possible association mappings, probably the most difficult and confusing is the bi-directional, many to many relationship that we are going to look at now. Don't fret though, Hibernate makes mapping a bi-directional, many to many relationship about as easy as it could possibly get. This is a big step forward for database persistence, as only a few years ago, many of the big vendor's container mapping tools actually ran out of steam when it came to properly managing complex many to many relationships.

Many to many relationships happen fairly frequently in enterprise applications, making it a fairly common pattern. For this tutorial, I'm going to rather glibly model the relationship between a Student and a college or university Course.

Conceptually, the student-course, many to many relationship, is fairly easy to conceptualize. For example, a single student named Bart could be in several college courses, such as Java-101, English-101 and UML-101. So, a student can be in many courses.

At the same time, a course, such as Java-101, can also have many students. Not only could Bart be enrolled in Java-101, but so could Kerri and Samantha and Leslie, etc. So, since the many relationship goes both ways, we call this a many to many relationship.

One of the challenges of dealing with many to many relationships is the fact that they manifest themselves in such a specific way at the database level, as compared to their implementation at the Java programming level. In a Java program, two classes maintaining a many to many relationship with each other simply maintain a list or collection of the corresponding class. So, with an example such as the Student has a many to many relationship with a Course, a student would maintain a collection listing the courses in which they are enrolled, and a course would maintain a collection or a list of attending students. However, at the database level, the implementation is much different.

At the database level, a many to many relationship between two classes is maintained with a third table that is known as a join table. Each table participating in the many to many relationship, which in this case would be a course and a student table, maintains its own primary key. However, any relationships between the two tables is maintained by a third, join table, where matching, or intersecting primary keys of course-student matches, are maintained. Again, the contrast between how many to many relationships are implemented in Java code, as opposed to how they are implemented at the database level, is a complicating factor. However, Hibernate does a pretty good job at simplifying the situation, allowing Java developers to concentrate on their code, while allowing the underlying database structure to elute naturally from the Java domain model.

A Left and Right Simplification

When mapping and working with a many to many relationship, one class in the relationship needs to make reference to the other, and vice-versa. This back and forth referencing can often be confusing. I always find it easier to conceptualize a many to many relationship with one class being on the left, one class being on the right, and the third, join class, placed in the middle. For this chapter, I am going to graph the class and table relationships in a left-right-middle manner; I'm even going to name the classes accordingly. The class names I will use in this chapter are LeftManyStudent and RightManyCourse, and the join table will simply be named join_table.

Also, it should be noted that there is no Java class that represents the join table, although there will be a leftmanystudent and rightmanycourse table to map to the LeftManyStudent and RightManyCourse Java classes.

Tables and Joins

Class Diagram

Database Entity Mappings

LeftManyStudent and RightManyCourse Classes

Because the annotation used for mapping a many to many relationship is probably the most complicated of them all, I'm going to keep the two classes we have here as simple as possible.

The LeftManyStudent class will have an id field of type long to track the primary key of the class, along with a simple String property called studentName. Furthermore, the LeftManyStudent class will have a property of type List named courses that keeps track of the many courses in which a student might be enrolled.

Similarly, the RightManyCourse class will have an id of type long, a String property called courseCode, and an object of type List to keep track of the many students enrolled in the course.

LeftManyStudent with the Initial Annotations

package com.examscam.mappings;
import java.util.*;
import javax.persistence.*;
@Entity
public class LeftManyStudent {

  long id;
  String studentName;
  List<RightManyCourse> courses = new Vector();

  @Id
  @GeneratedValue
  public long getId() {return id;}
  public void setId(long id) {this.id = id;}

  public List<RightManyCourse> getCourses(){return courses;}
  public void setCourses(List<RightManyCourse> righties) {
    this.courses = righties;
  }
  public String getStudentName() {return studentName;}
  public void setStudentName(String s) {studentName = s;}
}

RightManyCourse with the Initial Annotations

package com.examscam.mappings;
import java.util.*;import javax.persistence.*;
@Entity
public class RightManyCourse {
  long id;
  String courseCode;
  List<LeftManyStudent> students = new Vector();
  public List<LeftManyStudent> getStudents() {return students;}
  @Id
  @GeneratedValue
  public long getId() {return id;}
  public void setId(long id) {this.id = id;}
  public String getCourseCode() {return courseCode;}
  public void setCourseCode(String courseCode) {
    this.courseCode = courseCode;
  }
  public void setStudents(List<LeftManyStudent> lefties) {
    this.students = lefties;
  }
}
 

Student and Course Classes as Entities

Both the LeftManyStudent and RightManyCourse classes are individual entities whose state will be mapped back to respective database tables. As a result, both the Student and Course classes must have the required @Entity decoration before the class declaration, and the standard @Id and @GeneratedValue annotations before the getId() method. Of course, these are the standard annotations that we've been throwing on just about every JPA annotated POJO that we have created. What makes the Student and Course relationship interesting is the bi-directional many-to-many mapping that exists between them.

The fact that a Student can be enrolled in many Courses manifests itself in the form of a java.util.List named courses in the LeftManyStudent class. Subsequently, the getCourses() method in the LeftManyStudent class that returns the List of RightManyCourse instances must be decorated with the @ManyToMany annotation. Of course, this is a bi-directional, many to many relationship, with a join table that needs to be used to keep track of the relationship in the database. As a result, the getCourses() method not only needs the @ManyToMany annotation, but it needs the @JoinTable annotation to describe the mapping of the details of the Student and Course instances into the join table. The @JoinTable is a little intimidating the first time you see it in a bi-directional, many-to-many join. For now, just take a look at how the getCourses() method is decorated; an explanation will follow.

public class LeftManyStudent {   
 @ManyToMany
 @JoinTable(name = "join_table", 
 joinColumns = { @JoinColumn(name = "lmstudent_id")},
 inverseJoinColumns={@JoinColumn(name="rmcourse_id")}   
 )
  public List <RightManyCourse> getCourses() {
    return courses;
  }    
}
 

Documenting the Join Table

The manner in which the @JoinTable uses two nested @JoinColumn tags within the annotation is a little scary, but when you think about it, it actually makes a lot of sense.

To map a many to many relationship in a database, you need a join table. The join table we are going to use is simply named join_table, thus the sensible beginning of the @JoinTable annotation:

@JoinTable( name = "join_table",     )

Of course, we are currently coding this annotation in the LeftManyStudent class, and the @JoinTable tag wants to know the name of the column in the join_table that will be used to store the primary key of the LeftManyStudent instance. We'll use the letters ?l' and ?m' plus the word student, followed by an _id as the name of the column to store the LeftManyStudent id. Put it together, and you get lmstudent_id, and the first @JoinColumn part of the @JoinTable tag looks like this:

@JoinTable(name = "join_table", 
joinColumns={@JoinColumn(name= "lmstudent_id")},
     )

Of course, the first @JoinColumn annotation only tells Hibernate how to save the primary key of the LeftManyStudent class, not how to find out the name of the column that maps the Student to it's associated RightManyCourse. So, to help Hibernate process the inverse, Course to Student relationship, we add a second @JoinColumn annotation, but associate it with the inverseJoinColumns attribute of the @JoinTable annotation:

@ManyToMany
@JoinTable(name = "join_table", 
  joinColumns={ @JoinColumn(name="lmstudent_id")}, 
  inverseJoinColumns 
    ={ @JoinColumn (name = "rmcourse_id") } )

Mapping Both Side of the Many To Many

After mastering the @JoinTable annotation on the left hand side of the many-to-many relationship, understanding the right hand side of the relationship is a lead pipe cinch. Basically, it's the same, while at the same time, it's a little different.

Let's look at the LeftManyStudent mapping for its side of the many to many relationship:

public class LeftManyStudent {   
  @ManyToMany
  @JoinTable(name = "join_table",  
    joinColumns = { @JoinColumn(name = "lmstudent_id")},
      inverseJoinColumns={@JoinColumn(name="rmcourse_id")})
  public List<RightManyCourse> getCourses(){return courses;} 
}

Now, take a look at the RightManyCourse side of the many to many relationship.

public class RightManyCourse {
 @ManyToMany
 @JoinTable(name = "join_table", 
joinColumns={@JoinColumn(name="rmcourse_id")}, 
inverseJoinColumns={@JoinColumn(name="lmstudent_id")})
 public List<LeftManyStudent> getStudents(){return students;}
}

Comparing the Many Sides

You will notice that the @JoinTable annotation in the RightManyCourse class only differs from the @JoinTable annotation in the LeftManyStudent class in the ordering of the lmstudent_id and the rmcourse_id fields from the inverseJoinColumns and joinColumns attributes of the @JoinTable annotation. This obvious similarity makes sense, as both the LeftManyStudent and RightManyCourse classes, while on opposite sides, are participating in the same many to many relationship.

It's also worth noting that the values of lmstudent_id and rm_courseid, which are used in the @JoinTable annotation, do not actually manifest themselves as instance variables anywhere in the Java code. The JoinColumns are purely a manifestation of how a database, not a Java program, manages a many to many relationship.

Completed LeftManyStudent with Full Annotations

package com.examscam.mappings;
import java.util.*;
import javax.persistence.*;

@Entity
public class LeftManyStudent {

  long id;
  String studentName;
  List<RightManyCourse> courses = new Vector();


  @ManyToMany
  @JoinTable(name = "join_table", 
 joinColumns = { @JoinColumn(name = "lmstudent_id")},
 inverseJoinColumns={@JoinColumn(name="rmcourse_id")}   
  )
  public List<RightManyCourse> getCourses(){
    return courses;
  }
  public void setCourses(List<RightManyCourse> righties){
    this.courses = righties;
  }

  @Id
  @GeneratedValue
  public long getId() {return id;}
  public void setId(long id) {this.id = id;}

  public String getStudentName() {
    return studentName;
  }
  public void setStudentName(String s){
    studentName=s;
  }

}

Completed RightManyCourse with the Full Annotations

package com.examscam.mappings;

import java.util.*;
import javax.persistence.*;

@Entity
public class RightManyCourse {
  long id;
  String courseCode;
  List<LeftManyStudent> students = new Vector();

 @ManyToMany
 @JoinTable(name = "join_table", 
 joinColumns={@JoinColumn(name="rmcourse_id")}, 
inverseJoinColumns={@JoinColumn(name="lmstudent_id")})
  public List<LeftManyStudent> getStudents() {
    return students;
  }
  public void setStudents(List<LeftManyStudent> lefties){
    this.students = lefties;
  }
 
  @Id
  @GeneratedValue
  public long getId() {
    return id;
  }
  public void setId(long id) {
    this.id = id;
  }

  public String getCourseCode() {
    return courseCode;
  }
  public void setCourseCode(String courseCode) {
    this.courseCode = courseCode;
  }

}

Testing the Many to Many Mapping

As with all Hibernate mappings that leverage JPA annotations, the classes in question must be added to Hibernate's AnnotationConfiguration object in the central spot where the Hibernate Configuration is initialized.

AnnotationConfiguration config = 
                 new AnnotationConfiguration();
config.addAnnotatedClass(LeftManyStudent.class);
config.addAnnotatedClass(RightManyCourse.class);
config.configure();

Testing the Many to Many Mapping

To test the many to many mappings, we need to create instances of Student and Course objects. So, a Student object might be created like this:

LeftManyStudent student01 = new LeftManyStudent();

student01.setStudentName("Jim Jump");

A course object would be created like this:

RightManyCourse java101 = new RightManyCourse();

java101.setCourseCode("Java-101");

And once a student and a course exists, we can associate them with each other. So, we can have student01 enrolled in java101 by executing the following code:

java101.getStudents().add(student01);

To save this relationship to the database, we need to have each entity ?touch' the Hibernate session within the scope of a transaction. Using our HibernateUtil class, here's how we'd persist the fact that student01 is enrolled in java101.

  Session session = HibernateUtil.beginTransaction();
  session.save(student01);
  session.save(java101);
  HibernateUtil.commitTransaction();
 

A Full Many-to-Many Test Method

The following main method, when executed, will create many students, and have them associated with various courses. See if you can keep track of who is enrolled in which course ? the initials of the student's first and last name is a big hint.

public static void main (String args[]) {
 HibernateUtil.recreateDatabase();

  LeftManyStudent student01 = new LeftManyStudent();
  student01.setStudentName("Jim Jump");
  LeftManyStudent student02 = new LeftManyStudent();
  student02.setStudentName("Julie Camp");
  LeftManyStudent student03 = new LeftManyStudent();
  student03.setStudentName("Cam Johnson");
  LeftManyStudent student04 = new LeftManyStudent();
  student04.setStudentName("Marcus McKenzie");
  RightManyCourse java101 = new RightManyCourse();
  java101.setCourseCode("Java-101");
  RightManyCourse cplus101 = new RightManyCourse();
  cplus101.setCourseCode("C++ - 101");
  RightManyCourse math101 = new RightManyCourse();
  math101.setCourseCode("Math - 101");

  java101.getStudents().add(student01);
  java101.getStudents().add(student02);
  java101.getStudents().add(student03);
  cplus101.getStudents().add(student02);
  cplus101.getStudents().add(student03);
  math101.getStudents().add(student04);

  Session session = HibernateUtil.beginTransaction();
  session.save(student01);
  session.save(student02);
  session.save(student03);
  session.save(student04);
  session.save(java101);
  session.save(cplus101);
  session.save(math101);
  HibernateUtil.commitTransaction();
}
 

Running the Test Method

When Hibernate commits the transaction in the main method that tests the many to many mapping, it will spit out some interesting SQL, so long as you have enabled the hibernate.show_sql property in your hibernate.cfg.xml file. Here's the SQL that Hibernate generates:

Hibernate: 
insert into LeftManyStudent (studentName) values (?)
Hibernate: 
insert into LeftManyStudent (studentName) values (?)
Hibernate: 
insert into LeftManyStudent (studentName) values (?)
Hibernate: 
insert into LeftManyStudent (studentName) values (?)
Hibernate: 
insert into RightManyCourse (courseCode) values (?)
Hibernate: 
insert into RightManyCourse (courseCode) values (?)
Hibernate: 
insert into RightManyCourse (courseCode) values (?)
Hibernate: 
insert into join_table (rmcourse_id, lmstudent_id) values (?, ?)
Hibernate: 
insert into join_table (rmcourse_id, lmstudent_id) values (?, ?)
Hibernate: 
insert into join_table (rmcourse_id, lmstudent_id) values (?, ?)
Hibernate: 
insert into join_table (rmcourse_id, lmstudent_id) values (?, ?)
Hibernate: 
insert into join_table (rmcourse_id, lmstudent_id) values (?, ?)
Hibernate: 
insert into join_table (rmcourse_id, lmstudent_id) values (?, ?)

Simply by annotating our Java classes with the appropriate @ManyToMany annotations, and corresponding @JoinTable tags, Hibernate knows how to manage the primary keys of the classes participating in a many to many join, and it knows how to subsequently map those primary keys to a corresponding join table in order to permanently persist the relationship between instances.

Viewing the Results

After running the test method, viewing the contents of the database reveals three tables that have been populated with data, namely the leftmanystudent, rightmanycourse and the join_table.

As you can see, individual students are still saved in the leftmanystudent table, and courses are stored in the rightmanycourse table. However, the fact that Julie Camp (id of 2)` is enrolled in Java (id of 1) 101 and C++ 101 (id of 2) is maintained by the join table, as it maintains the matching primary keys of entities in the student and course tables. The key lines of code that map Julie to the Java 101 and C++ 101 courses is below:

  LeftManyStudent student02 = new LeftManyStudent();
  student02.setStudentName("Julie Camp");

  RightManyCourse java101 = new RightManyCourse();
  java101.setCourseCode("Java-101");
  RightManyCourse cplus101 = new RightManyCourse();
  cplus101.setCourseCode("C++ - 101");

  java101.getStudents().add(student02);
  cplus101.getStudents().add(student02);

  session.save(student02);
  session.save(java101);
  session.save(cplus101);
		
		

hibernate java hibernate spring hibernate hibernate cache hibernate class hibernate collection hibernate configuration hibernate database hibernate dialect hibernate download hibernate example hibernate mapping hibernate query hibernate sql hibernate tutorial hibernate xml struts hibernate xp hibernate 3 hibernate 3.0 hibernate api hibernate caching hibernate cfg xml hibernate dao hibernate examples hibernate framework hibernate generator hibernate in action hibernate jdbc hibernate list hibernate one to one hibernate plugin hibernate properties hibernate tool hibernate tools hibernate training hibernate tutorials java persistence with hibernate jboss hibernate linux hibernate standby hibernate ubuntu hibernate xdoclet hibernate hibernate synchronizer computer hibernate disable hibernate enable hibernate hibernate 2 hibernate 3.2 hibernate annotation hibernate annotations hibernate bag hibernate batch hibernate blob hibernate button hibernate c3p0 hibernate cascade hibernate command hibernate composite id hibernate composite key hibernate config hibernate connection hibernate criteria hibernate date hibernate delete hibernate discriminator hibernate documentation hibernate ehcache hibernate entitymanager hibernate enum hibernate fetch hibernate file hibernate filter hibernate flush hibernate formula hibernate forum hibernate hbm hibernate hbm2ddl hibernate hbm2ddl auto hibernate hql hibernate id hibernate in vista hibernate inheritance hibernate insert hibernate interceptor hibernate interview questions hibernate inverse hibernate javadoc hibernate join hibernate jpa hibernate lazy hibernate lazy loading hibernate load hibernate logging hibernate many to many hibernate many to one hibernate map hibernate mapping file hibernate merge hibernate mode hibernate named query hibernate order hibernate order by hibernate org hibernate performance hibernate problems hibernate property hibernate proxy hibernate query language hibernate reference hibernate restrictions hibernate reverse engineering hibernate save hibernate saveorupdate hibernate search hibernate select hibernate sequence hibernate session hibernate sessionfactory hibernate set hibernate shortcut hibernate show_sql hibernate source hibernate sql query hibernate stored procedure hibernate template hibernate timestamp hibernate transaction hibernate type hibernate update hibernate usertype hibernate validator hibernate version how to hibernate laptop hibernate net sf hibernate netbeans hibernate org hibernate dialect org hibernate session sleep hibernate sleep vs hibernate spring and hibernate standby vs hibernate turn off hibernate vista hibernate what is hibernate windows hibernate windows xp hibernate all 150 Help java spring apache xml ajax cache cmp j2ee s truts tomcat ejb jboss jsf maven primary key ruby on rails foreign key hibernation ibatis one to one spring framework xdoclet hql hybernate jdo many to many middlegen ojb one to many

eXTReMe Tracker