In this tutorial we will write a simple Java project to demonstrate Hibernate one to Many Mapping using Java Annotations. In my previous article I have explained Hibernate one to Many Mapping using XML. The main difference between these two examples would be the hibernate configuration files and annotations. Otherwise both the articles trying the same example.
We will first create a Java project using Maven and then will add Hibernate on it. If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on Java topics, please subscribe here. If you are beginner for hibernate, please read the articles about introduction to hibernate, interceptors in hibernate and spring & hibernate integration. We also recommend good reference books for learning hibernate in our post about hibernate books.
One To Many Relationship
Also known as a many-to-one relationship, this occurs when the maximum of one multiplicity is one and the other is greater than one. An example is the relationship between Person and Phone.
Consider the following relationship:
According to the relationship each Person can have a any number of phone numbers. But each phone number will be associated with only one person. Hence we will need two tables namely PERSON and PHONE to create this relation. In Hibernate, one-to-many relationship between entities can be created by 2 different techniques. These techniques are:
- Using foreign key association: In this association, we can have a foreign key column in PHONE table i.i PERSONID. This column will refer to primary key of PERSON table. This way no two phone numbers can be associated with multiple persons. Obviously, phone number needs to be unique for enforcing this restriction. The example below in this post demonstrates this asscociation. The relational model is shown below:
- Using a common join table: In this association, we can have a common join table lets say PERSON_PHONE. This table will have two column i.e. PERSON_ID which will be foreign key referring to primary key in PERSON table and similarly PHONE_ID which will be foreign key referring to primary key of PHONE table.
The relational model is shown below:
Technologies Used:
Following are the tools and technologies required for this project:
- Java JDK 5 or above
- Eclipse IDE 3.2 or above
- Maven 3.0 or above
- Hibernate 3.0 or above (Hibernate Downloads)
- MySQL 5 above (MySql Downloads)
1.Environment Setup
Refer post Hibernate, Maven and HSQL – Example Project (XML Mapping) for environment setup (follow steps 1,2 and 3). Pass the following command in the step.1, to create a java project using Maven:
mvn archetype:generate -DgroupId=net.javabeat.hibernate -DartifactId=HibernateOneToManyAnnotations -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
2. Adding dependencies to pom.xml
We need to add the Hibernate, MYSQL and some other dependencies to the Maven pom.xml as shown below:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>net.javabeat.hibernate</groupId> <artifactId> HibernateOneToManyAnnotations</artifactId> <packaging>jar</packaging> <version>1.0-SNAPSHOT</version> <name> HibernateOneToManyAnnotations</name> <url>http://maven.apache.org</url> <dependencies> <!-- Hibernate library dependency start --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate</artifactId> <version>4.1.9.Final</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.10</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-annotations</artifactId> <version>3.3.1.GA</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.1.1</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>2.2</version> </dependency> <dependency> <groupId>asm</groupId> <artifactId>asm</artifactId> <version>4.0</version> </dependency> <dependency> <groupId>dom4j</groupId> <artifactId>dom4j</artifactId> <version>1.6.1</version> </dependency> <dependency> <groupId>ehcache</groupId> <artifactId>ehcache</artifactId> <version>1.2.3</version> </dependency> <dependency> <groupId>hibernate-tools</groupId> <artifactId>hibernate-tools</artifactId> <version>3.2.3.GA</version> </dependency> <dependency> <groupId>jta</groupId> <artifactId>jta</artifactId> <version>1.1</version> </dependency> <dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.11</version> </dependency> <dependency> <groupId>oscache</groupId> <artifactId>oscache</artifactId> <version>2.1</version> </dependency> <dependency> <groupId>persistence-api</groupId> <artifactId>persistence-api</artifactId> <version>1.0</version> </dependency> <!-- Hibernate library dependecy end --> </dependencies> </project>
As a next step, let’s execute the following command so that maven will download all the required JARs and add the same to eclipse classpath. The command line point to the directory C:\HibernateProject\ HibernateOneToManyAnnotations and execute the following command:
mvn eclipse:eclipse
3. Create Model Classes
As we sould be using annotations, we need to only write the model classes:
src\main\java\net\javabeat\hibernate\Person.java and src\main\java\net\javabeat\hibernate\Phone.java.
The contents of the model classes are as below
Person.java
package net.javabeat.hibernate; import java.io.Serializable; import java.util.HashSet; import java.util.Set; import javax.persistence.CascadeType; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.OneToMany; import javax.persistence.Table; import javax.persistence.UniqueConstraint; /** * Model class for Person */ @Entity @Table(name="Person" , uniqueConstraints = { @UniqueConstraint(columnNames = "ID"), @UniqueConstraint(columnNames = "NAME") }) public class Person implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "ID", unique = true, nullable = false) private Long id; @Column(name = "NAME") private String name; @OneToMany(cascade = CascadeType.ALL, mappedBy = "person") private Set<Phone> personPhoneNumbers = new HashSet<Phone>(); public Person(String name, Set<Phone> personPhoneNumbers) { super(); this.name = name; this.personPhoneNumbers = personPhoneNumbers; } public Person() { } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Set<Phone> getPersonPhoneNumbers() { return personPhoneNumbers; } public void setPersonPhoneNumbers(Set<Phone> personPhoneNumbers) { this.personPhoneNumbers = personPhoneNumbers; } public void addPhone(Phone phone) { phone.setPerson(this); this.personPhoneNumbers.add(phone); } }
Phone.java
package net.javabeat.hibernate; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.Table; import javax.persistence.UniqueConstraint; @Entity @Table(name = "PHONE", uniqueConstraints = { @UniqueConstraint(columnNames = "ID") }) public class Phone implements Serializable { @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "ID", unique = true, nullable = false) private Long id; @Column(name = "CONTACTNUMBER", unique = true, nullable = false, length = 100) private String contactnumber; @Column(name = "PHONETYPE") private String phonetype; @ManyToOne @JoinColumn(name = "personId") private Person person; public Phone() { } public Phone(String contactnumber, String phonetype) { super(); this.contactnumber = contactnumber; this.phonetype = phonetype; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getContactnumber() { return contactnumber; } public void setContactnumber(String contactnumber) { this.contactnumber = contactnumber; } public String getPhonetype() { return phonetype; } public void setPhonetype(String phonetype) { this.phonetype = phonetype; } public Person getPerson() { return person; } public void setPerson(Person person) { this.person = person; } }
Details of the above files are as below:
- In the file Person.java, we have made the one to many association using the annotation @OneToMany(cascade = CascadeType.ALL, mappedBy = “person”). Here mappedBy attribute is used to define the field that “owns” the relation on the owning side (the side that holds the foreign key i.e. the Many side in a one-to-many. Here it is the person field in Phone entity). @ManyToOne annotation is used in the Phone class.
- The @JoinColumn annotation should be defined on the owning side only (in our case it is the Phone entity).
4. Adding Hibernate Configuration file
As a next step let’s add the hibernate.cfg.xml to the directory:/src/main/resources . Write the new file hibernate.cfg.xml in this directory. The hibernate.cfg.xml is as follows:
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings, Connect to MYSQL --> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/manisha</property> <property name="connection.username">root</property> <property name="connection.password">root</property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <property name="show_sql">true</property><property name="format_sql">true</property> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <!--create the database schema on startup if required --> <property name="hbm2ddl.auto">create</property> <mapping class="net.javabeat.hibernate.Person"></mapping> <mapping class="net.javabeat.hibernate.Phone"></mapping> </session-factory> </hibernate-configuration>
In the above file we have set the database connection to MYSQL database . The show_sql option, if set to true will display all the executed SQL queries on the console. The property hbm2ddl.auto , if set to create, creates the schema, destroying the previous data. At the end of the file we add model classes, Person and Phone to the configuration.
Note : In case you want to use any other database then, you need to change these properties – “dialect”, “connection.driver_class”, “connection.url”, “connection.username”, and “connection.password”.
5. Create Utility class
Next, we will write a utility class to take care of Hibernate start up and retrieve the session easily. We will write the file src\main\java\net\javabeat\hibernate\HibernateUtil.java as below:
package net.javabeat.hibernate; import org.hibernate.SessionFactory; import org.hibernate.cfg.AnnotationConfiguration; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { sessionFactory = new AnnotationConfiguration().configure() .buildSessionFactory(); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }
6. Revise the App class
Next we will revise the App.java (generated by Maven). This class tests the one-to-many relationship by creating and listing the person names and corresponding phone numbers as below:
package net.javabeat.hibernate; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.hibernate.HibernateException; import org.hibernate.Session; import org.hibernate.Transaction; /** * Main class * */ public class App { public static void main(String[] args) { System.out .println("Maven + Hibernate + SQL One to Many Using Annotations "); Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); App app = new App(); app.savePersonInfo("Manisha"); app.listPersonInfo(); } public Long savePersonInfo(String personName) { Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Long personId = null; Transaction transaction = null; try { transaction = session.beginTransaction(); Person person = new Person(); person.setName(personName); Phone ph1 = new Phone(); Phone ph2 = new Phone(); ph1.setContactnumber("4100000"); ph1.setPhonetype("Landline"); ph2.setContactnumber("988000045"); ph2.setPhonetype("Mobile"); person.addPhone(ph1); person.addPhone(ph2); session.save(person); transaction.commit(); } catch (HibernateException e) { transaction.rollback(); e.printStackTrace(); } finally { session.close(); } return personId; } /* * Lists the person's from database table */ public void listPersonInfo() { Session session = HibernateUtil.getSessionFactory().openSession(); Transaction transaction = null; try { transaction = session.beginTransaction(); @SuppressWarnings("unchecked") List<Person> personList = session.createQuery("FROM Person").list(); System.out.println("List size: " + (personList).size()); for (Iterator iterator = personList.iterator(); iterator.hasNext();) { Person person = (Person) iterator.next(); Set<Phone> ph = new HashSet<Phone>(); ph = person.getPersonPhoneNumbers(); for (Phone p : ph) { System.out.println("***************************"); System.out.println(person.getName()); System.out.println(" Phone Type: " + p.getPhonetype()); System.out .println(" Phone Number: " + p.getContactnumber()); System.out.println("***************************"); } } transaction.commit(); } catch (HibernateException e) { transaction.rollback(); e.printStackTrace(); } finally { session.close(); } } }
Here the savePersonInfo() method is used to save a new Person object and Phone object to the database.
The listPersonInfo() method is used to list name of each person in PERSON table and their corresponding phone numbers and type from PHONE table. Here we use Hibernate Query Language (HQL). The query “from Person” returns a list of all the data in the PERSON table and their corresponding phone numbers from PHONE table. Note that in the HQL we only specify the java class names and not the table names. Later, using the for loop we iterate the list the data from Person and corresponding Phone table and hence display them on the console.
8. Final project structure
Once you have created all these source files, your project structure should look like following:
9. Execution of the above code
Now let us execute the code we created above. Let’s run the App class.
Right click on App.java >Run As > Java Application.
On start of each thread, a database schema will be created and the following actions will happen.
Output on the console:
Following output is displayed on the console:
Maven + Hibernate + SQL One to Many Using Annotations log4j:WARN No appenders could be found for logger (org.hibernate.cfg.annotations.Version). log4j:WARN Please initialize the log4j system properly. Hibernate: insert into Person (NAME) values (?) Hibernate: insert into PHONE (CONTACTNUMBER, personId, PHONETYPE) values (?, ?, ?) Hibernate: insert into PHONE (CONTACTNUMBER, personId, PHONETYPE) values (?, ?, ?) Hibernate: select person0_.ID as ID0_, person0_.NAME as NAME0_ from Person person0_ List size: 1 Hibernate: select personphon0_.personId as personId1_, personphon0_.ID as ID1_, personphon0_.ID as ID1_0_, personphon0_.CONTACTNUMBER as CONTACTN2_1_0_, personphon0_.personId as personId1_0_, personphon0_.PHONETYPE as PHONETYPE1_0_ from PHONE personphon0_ where personphon0_.personId=? *************************** Manisha Phone Type: Mobile Phone Number: 988000045 *************************** *************************** Manisha Phone Type: Landline Phone Number: 4100000 ***************************
Using a Common Join Table
This technique uses a join table to store the associations between Person and Phone entities (as seen in the entity relation diagram above).
We use @JoinTable annotation to create the one-to-many relationship between the Person and Phone entities. Following needs to be added to the Person entity:
@OneToMany @JoinTable( name="Person_Phone", joinColumns = @JoinColumn( name="person_id"), inverseJoinColumns = @JoinColumn( name="phone_id") ) public Set<Phone> getPersonPhoneNumbers() {
@manytoone annotation need not be set in the Phone entity, hence making it unidirectional.
Summary
In my previous article I have explained Hibernate one to Many Mapping using Java Annotations. The main difference between these two examples would be the hibernate configuration files and annotations. Otherwise both the articles trying the same example.
In this post we demonstrated one-to-many relation using Java annotation. We discussed about various techniques of one-to-many associations. We initially created a Java project using Maven, made it compatible with eclipse. Then we created model classes using annotations (foreign key association). We then set the values in our main class(App.java), which in turn added the values to respective tables. We also listed the data from the tables. In the next post we shall see an example of Hibernate Many-to-Many mapping(using XML mpping).If you have any questions, please post it in the comments section. If you are interested in receiving the future articles on Java topics, please subscribe here