In the following example, we will be going through the bi-directional One-to-Many association using Hibernate. We will be using the Employee and PhoneNumbers table where each Employee will have one or more phone numbers associated with him/her.
Schema Creation:
We will be creating two tables Employee and PhoneNumbers. The PhoneNumbers table has a foreign key reference to the Employee table.
CREATE TABLE EMPLOYEE (
EMP_ID INTEGER(5) PRIMARY KEY DEFAULT 1,
EMP_NAME VARCHAR(30) NOT NULL,
EMP_DOB DATE NOT NULL
);
CREATE TABLE PHONENUMBERS (
PH_ID INTEGER(5) PRIMARY KEY DEFAULT 1,
PH_NUMBER VARCHAR(10) NOT NULL,
EMP_ID INTEGER(5) NOT NULL,
FOREIGN KEY (EMP_ID) REFERENCES EMPLOYEE (EMP_ID)
);
HBM Files Creation:
Employee.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
<class name="Employee" table="EMPLOYEE">
<id name="empId" column="EMP_ID" type="integer">
<generator class="increment"></generator>
</id>
<property name="empName" column="EMP_NAME" not-null="true"
type="string"></property>
<property name="empDOB" column="EMP_DOB" not-null="true"
type="date"></property>
<set name="phoneNumbers" table="PHONENUMBERS" cascade="all"
lazy="false" inverse="true" order-by="PH_ID ASC">
<key column="EMP_ID" not-null="true"></key>
<one-to-many class="PhoneNumbers" />
</set>
</class>
</hibernate-mapping>
PhoneNumbers.hbm.xml:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
<class name="PhoneNumbers" table="PHONENUMBERS">
<id name="phId" column="PH_ID" type="integer">
<generator class="increment"></generator>
</id>
<property name="phoneNo" column="PH_NUMBER" not-null="true"
type="string"></property>
<many-to-one name="employee" column="EMP_ID"
not-null="true" cascade="all" class="Employee" lazy="false"></many-to-one>
</class>
</hibernate-mapping>
Java Files:
Employee.java:
package org.mybusiness.pojos;
import java.io.Serializable;
import java.util.Date;
import java.util.LinkedHashSet;
import java.util.Set;
public class Employee implements Serializable {
private static final long serialVersionUID = 4451804446997564426L;
private int empId;
private String empName;
private Date empDOB;
// Hibernate expects interfaces like Set, Map, List to be the declaration
// because while doing retrieve operations Hibernate uses its own Set, etc
// to fill up the contents in this variable
private Set<PhoneNumbers> phoneNumbers;
public Employee() {
phoneNumbers = new LinkedHashSet<PhoneNumbers>();
}
public int getEmpId() {
return empId;
}
public void setEmpId(int empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Date getEmpDOB() {
return empDOB;
}
public void setEmpDOB(Date empDOB) {
this.empDOB = empDOB;
}
public Set<PhoneNumbers> getPhoneNumbers() {
return phoneNumbers;
}
public void setPhoneNumbers(Set<PhoneNumbers> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
public void addPhoneNumber(PhoneNumbers phoneNumber) {
this.phoneNumbers.add(phoneNumber);
}
}
PhoneNumbers.java:
package org.mybusiness.pojos;
import java.io.Serializable;
public class PhoneNumbers implements Serializable {
private static final long serialVersionUID = -3505306499633395745L;
private int phId;
private String phoneNo;
// Adding Bi-directionality.
private Employee employee;
public int getPhId() {
return phId;
}
public void setPhId(int phId) {
this.phId = phId;
}
public String getPhoneNo() {
return phoneNo;
}
public void setPhoneNo(String phoneNo) {
this.phoneNo = phoneNo;
}
public Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
Functionalities:
Create Employee:
Approach 1:
public void createEmployeeBidirApproach1() {
HibernateTemplate ht = new HibernateTemplate(sessionFactory);
Session s = ht.getSessionFactory().openSession();
Transaction tx = s.beginTransaction();
try {
// Create an employee
Employee emp = new Employee();
emp.setEmpName("Peter");
emp.setEmpDOB(Calendar.getInstance().getTime());
// Save the Employee and get the Primary Key
Integer key = (Integer) s.save(emp);
PhoneNumbers phNo = new PhoneNumbers();
phNo.setPhoneNo("8765432190");
phNo.setEmployee(emp); // Set the foreign key.
// Save the phone number
s.save(phNo);
phNo = new PhoneNumbers();
phNo.setPhoneNo("9988776655");
phNo.setEmployee(emp);// Save the phone number
// Save the phone number
s.save(phNo);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
s.close();
}
}
Approach 2:
public void createEmployeeBidirApproach2() {
HibernateTemplate ht = new HibernateTemplate(sessionFactory);
Session s = ht.getSessionFactory().openSession();
Transaction tx = s.beginTransaction();
try {
Employee emp = new Employee();
emp.setEmpName("Jake");
emp.setEmpDOB(Calendar.getInstance().getTime());
// Save Employee and get the key
Integer key = (Integer) s.save(emp);
PhoneNumbers phNo = new PhoneNumbers();
phNo.setPhoneNo("7865765412");
phNo.setEmployee(emp);
emp.addPhoneNumber(phNo);
phNo = new PhoneNumbers();
phNo.setPhoneNo("7766776677");
phNo.setEmployee(emp);
emp.addPhoneNumber(phNo);
// Save the employee again with the phone numbers added
s.save(emp);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
s.close();
}
}
Retrieve Employee:
public void getAllEmployees() {
HibernateTemplate ht = new HibernateTemplate(sessionFactory);
DetachedCriteria criteria = DetachedCriteria.forClass(Employee.class,
"emp");
criteria.add(Restrictions.le("emp.empId", 10));
// NOTE: LEFT_JOIN eliminates the selection of all phone numbers from
// the phonenumbers table. This is necessary when we want to filter out
// the result set from the dependent entity
DetachedCriteria child = criteria.createCriteria("emp.phoneNumbers",
"ph", CriteriaSpecification.LEFT_JOIN);
child.add(Restrictions.ilike("ph.phoneNo", "2", MatchMode.END));
child.add(Restrictions.le("ph.phId", 10));
child.addOrder(Order.desc("ph.phId"));
// NOTE: The result transformer ensures that the result contains only
// one Employee object with set of phone numbers. If this transformer is
// not used, then the result set would be repeated by the number of
// phone numbers present in the set.
criteria
.setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);
List<Employee> employees = ht.findByCriteria(criteria);
int count = 1;
for (Employee employee : employees) {
System.out.println("Employee Index : " + count++);
System.out.println("----------------------------");
printEmployee(employee);
}
}
public void getPhoneNumbersForEmployee() {
Integer empId = 5;
HibernateTemplate ht = new HibernateTemplate(sessionFactory);
DetachedCriteria criteria = DetachedCriteria.forClass(
PhoneNumbers.class, "ph");
criteria.createAlias("ph.employee", "emp");
criteria.add(Restrictions.eq("emp.empId", 5));
List<PhoneNumbers> phonenumbers = ht.findByCriteria(criteria);
for (PhoneNumbers phNo : phonenumbers) {
System.out.println(phNo.getPhId() + ":" + phNo.getPhoneNo() + ":"
+ phNo.getEmployee().getEmpName());
System.out.println();
}
}
private void printEmployee(Employee employee) {
System.out.println("Employee Id : " + employee.getEmpId());
System.out.println("Employee Name : " + employee.getEmpName());
System.out.println("Employee DOB : " + employee.getEmpDOB());
Set<PhoneNumbers> phNos = employee.getPhoneNumbers();
System.out.println(phNos.getClass());
if (phNos != null) {
for (PhoneNumbers phNo : phNos) {
System.out.println("PhNo : " + phNo.getPhId() + ", "
+ phNo.getPhoneNo());
}
}
System.out.println("---------------------------"
+ "--------------------------");
}