In this post under Hibernate, I will explain how to create a bidirectional one to many association between objects using a mapping file with an example.
For our example, we will create the below two tables.
Data Definition Language
CREATE TABLE `series2` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`description` VARCHAR(100) NOT NULL,
PRIMARY KEY (`id`)
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=DYNAMIC
AUTO_INCREMENT=1
;
CREATE TABLE `season2` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(50) NOT NULL,
`description` VARCHAR(100) NOT NULL,
`series_id` INT(11) NULL DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `FK_season_series` (`series_id`),
CONSTRAINT `season2_ibfk_1` FOREIGN KEY (`series_id`) REFERENCES `series2` (`id`) ON UPDATE CASCADE
)
COLLATE='utf8_general_ci'
ENGINE=InnoDB
ROW_FORMAT=DYNAMIC
AUTO_INCREMENT=1
;
According to above sql code, I have created two tables “series2” and “season2”. In Object Oriented world, there will be one to many association between “series2” and “season2”. In other words one “series2” instance will have multiple instances of “season2”. So to create a one to many association in RDBMS, I have added a foreign key “series_id” column in “season2” table. This foreign key will refer to primary column in “series2” table.
Next we will create java classes for the above tables
Series2
import java.util.Set;
public class Series2 {
private int id;
private String name;
private String description;
private Set seasons;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Set getSeasons() {
return seasons;
}
public void setSeasons(Set seasons) {
this.seasons = seasons;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(id).append(":");
sb.append(name).append(":");
sb.append(description);
return sb.toString();
}
}
Season2
public class Season2 {
private int id;
private String name;
private String description;
private Series2 series;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Series2 getSeries() {
return series;
}
public void setSeries(Series2 series) {
this.series = series;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(id).append(":");
sb.append(name).append(":");
sb.append(description).append(":");
sb.append(this.getSeries());
return sb.toString();
}
}
Since we are creating an bidirectional one to many association meaning the navigation will be from both side (i.e., one to many side and many to one side). In the Series2 class code, we have added “seasons” property of type Set containing “Season2” class instances (one to many side reference). We have also added “series” property in Season2 class to refer Series2 instances from Season2 instances (many to one side reference). Series2 class is on one side and Season2 class is on many side.
Next we add hbm.xml file for the above java classes
Season2.hbm.xml
1 <?xml version="1.0"?>
2 <!DOCTYPE hibernate-mapping PUBLIC
3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
5 <hibernate-mapping>
6 <class name="Season2" table="Season2">
7 <id type="int" name="id" column="id">
8 <generator class="native"/>
9 </id>
10 <property name="name" column="name" type="string"/>
11 <property name="description" column="description" type="string"/>
12 <many-to-one name="series" class="Series2" column="series_id"/>
13 </class>
14 </hibernate-mapping>
In Season2.hbm.xml we add the xml snippet (refer to line 12) to create a many to one side relationship between Season2 and Series2.
In many to one element, name attribute’s value matches the series property added in Season2 class. The class attributes value will have class name of Series2 class and column attribute’s value will be equal to “series_id” foreign key column name in season2 table.
Series2.hbm.xml
1 <?xml version="1.0"?>
2 <!DOCTYPE hibernate-mapping PUBLIC
3 "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
4 "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
5 <hibernate-mapping>
6 <class name="Series2" table="Series2">
7 <id type="int" name="id" column="id">
8 <generator class="native"/>
9 </id>
10 <property name="name" column="name" type="string"/>
11 <property name="description" column="description" type="string"/>
12 <set name="seasons" cascade="all">
13 <key column="series_id"/>
14 <one-to-many class="Season2"/>
15 </set>
16 </class>
17 </hibernate-mapping>
In the above xml file, to create a one to many mapping we add the xml code starting from line 12 to 15 as shown below
12 <set name="seasons" cascade="all">
13 <key column="series_id"/>
14 <one-to-many class="Season2"/>
15 </set>
1) The set element’s name attribute’s value matches with the property name “seasons” in Series2.java file.
2) The column attribute’s value in key element, matches with the foreign key column name “series_id” added in “season2” table.
3) The one-to-many element’s class attribute’s value will have the class name of the class at the many side of the relationship. In this case it will be “Season2”.
Below is hibernate configuration file for your reference
hibernate.cfg.xml
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/examples</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- <property name="hibernate.hbm2ddl.auto">create</property> -->
<property name="hibernate.show_sql">true</property>
<mapping resource="Series2.hbm.xml"/>
<mapping resource="Season2.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Below is the main code
Main Code
1 import java.util.HashSet;
2 import java.util.Set;
3
4 import org.hibernate.Session;
5 import org.hibernate.SessionFactory;
6
7 public class HibernateDemo11 {
8 public static void main(String[] args) {
9 SessionFactory sessionFactory = HibernateUtil.createSessionFactory();
10
11 Series2 series = new Series2();
12 series.setName("Monk");
13 series.setDescription("Monk");
14
15 Season2 season1 = new Season2();
16 season1.setName("Season1");
17 season1.setDescription("Season1");
18 season1.setSeries(series);
19
20 Season2 season2 = new Season2();
21 season2.setName("Season2");
22 season2.setDescription("Season2");
23 season2.setSeries(series);
24
25 Set set = new HashSet();
26 set.add(season1);
27 set.add(season2);
28
29 series.setSeasons(set);
30
31 Session session = sessionFactory.openSession();
32 session.beginTransaction();
33 int id = (Integer)session.save(series);
34 session.getTransaction().commit();
35 session.close();
36
37 series = null;
38
39 session = sessionFactory.openSession();
40 series = session.load(Series2.class, id);
41 for(Season2 season : series.getSeasons()) {
42 System.out.println(season);
43 }
44 session.close();
45 HibernateUtil.shutdown();
46 }
47 }
In the main code, at line 11 I create Series2 instance, at line 15 and 20, I create two instances of Season2.
At line 18 and 23, I set the series property of season1 and season2 instance to series instance. This creates a many to one reference.
At line 25 I create a set and add season1, season2 to the set.
At line 29 I assign the set to series instance to create a one to many reference.
At line 33 I save the series instance.
At line 40 I load the saved series instance and print them out in the console.