One-to-Many Example Hibernate

One-to-Many Hibernate

Earlier in hierarchical relationships, when beans with hierarchical relationship exist, we created tables with different strategies like table-per-subclass etc. Now the other way is we will have tables with foreign key relational associations, let us create bean classes accordingly and insert records to all the tables.

The most unidirectional relational associations are

1. One-to-many
2. Many-to-one
3. One-to-one
4. many-to-many (with Set)
5. many-to-many (with Map)

Let us discuss one by one; now the first one.

  1. One-To-Many Relationship: A relationship in which each record in one table is linked (or associated) to multiple records in another table. To talk in Java style, one object of one Java class is related to multiple objects of another Java class. The two tables are associated with a foreign key. The primary key of one table is the foreign key for another table.
  2. Concept: One department may contain many employees. Here, department is table dept and employee is table employee.
  3. Association in tables: dept_id of dept table is declared as foreign key in employee table. That is, dept_id exist in both the tables.
  4. Bean coding: Let us see how to implement the above association in Java classes (beans). Two beans exist, Dept and Employee. As department contains many employees, many Employee objects are created and added to a java.util.Set. This set is added to Dept object.

Observe the variables of Dept class.

private int deptId;
private String deptName;
private Set employees;

Dept class contains a Set of employees. This is how foreign key representation of tables is represented in bean classes.

After knowing this much, let us go into the programming.

Create two tables (with following SQL commands) dept and employee and keep ready.

SQL> create table dept (dept_id integer, dept_name varchar(15), primary key (dept_id));

SQL> create table employee(employee_id integer, employee_name varchar(15), dept_id integer, primary key (employee_id), foreign key(dept_id) references dept(dept_id));

Note: "dept_id integer" must exist as foreign key in employee table to which data will be fed from dept table. This we do it in mapping XML file

Now, Write the two beans.

1. File Name: Dept.java

import java.util.Set;
public class Dept 
{
  private int deptId;
  private String deptName;
  private Set employees;

  public Dept() 
  {
    // TODO Auto-generated constructor stub
  }
  public int getDeptId() 
  {
    return deptId;
  }
  public void setDeptId(int deptId) 
  {
    this.deptId = deptId;
  }
  public String getDeptName() 
  {
    return deptName;
  }
  public void setDeptName(String deptName) 
  {
    this.deptName = deptName;
  }
  public Set getEmployees() 
  {
    return employees;
  }
  public void setEmployees(Set employees) 
  {
    this.employees = employees;
  }
}

private Set employees;

As Dept may contain many employees, all the employees present in the dept are created as Set and added to Dept class. This is how one to many association of tables is implemented in Java classes. Here one is Dept class (represented by dept table) and many is Employee (represented by employee table). Set is preferred as one employee id cannot be duplicated (if duplicated, as in some cases (one person can order the same item number of times), List can be preferred)).

This is represented in mapping file as follows:


  
    
  
  
  
    
    
  

set name="employees": The value of name attribute should be the reference variable of Set declared in Dept class (private Set employees). A novice gets confusion here only.

The <key> element in mapping file represents always a foreign key. Here, the foreign key is dept_id declared in employee table. As per this foreign key dept_id, the Set elements of Dept class are populated into employee table. This must be very clear as the whole logic of association lies here.

cascade=”persist, delete”

The cascade attribute populates the data to other table records. The cascade, here, works only for persist (inserting) and delete (deleting) operations. If cascading is required for all the operations, write as follows:

cascade=”all”

2. File Name: Employee.java

public class Employee 
{
  private int employeeId;
  private String employeeName;
	
  public Employee() 
  {
    // TODO Auto-generated constructor stub
  }
  public int getEmployeeId() 
  {
    return employeeId;
  }
  public void setEmployeeId(int employeeId) 
  {
    this.employeeId = employeeId;
  }
  public String getEmployeeName() 
  {
    return employeeName;
  }
  public void setEmployeeName(String employeeName) 
  {
    this.employeeName = employeeName;
  }
}

3. File Name: hibernate.cfg.xml








  
    org.hibernate.dialect.Oracle9Dialect
  
  
    jdbc:oracle:thin:@localhost:1521:orcl1
  
  scott
  tiger
  
    oracle.jdbc.driver.OracleDriver
  
  
    SNRaoConnection
  
  update
  true
  



<property name="hbm2ddl.auto">update</property>

Actually, the above statement is not required as we have created table manually. I prefer to have as a safety measure when a column is missed, it is created implicitly.

4. File Name: dept.hbm.xml



	




    
      
    
    
    
      
      
    


    
      
    
    



5. Client program: Client1.java

import java.util.Set;
import java.util.HashSet;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

public class Client1 
{
  public static void main(String[] args) 
  {
    // TODO Auto-generated method stub
		
    Configuration c = new Configuration();
    c.configure("/hibernate.cfg.xml");
		
    SessionFactory sf=c.buildSessionFactory();
		
    Session session = sf.openSession();
    Transaction trans = session.getTransaction();
    trans.begin();
						// create some Employee object
    Employee emp1 = new Employee();
    emp1.setEmployeeId(1);
    emp1.setEmployeeName("S N Rao");

    Employee emp2 = new Employee();
    emp2.setEmployeeId(2);
    emp2.setEmployeeName("Sumathi");
	
    Employee emp3 = new Employee();
    emp3.setEmployeeId(3);
    emp3.setEmployeeName("Sasi");

    Set  emps = new HashSet();
    emps.add(emp1);   		               // add Employee object to Set
    emps.add(emp2);
    emps.add(emp3);

    Dept dept = new Dept();
    dept.setDeptId(1234);
    dept.setDeptName("Production");
    dept.setEmployees(emps);  	               // add Set object to Dept object
    session.persist(dept);
    trans.commit();
    System.out.println("Records inserted");
  }
}

Transaction trans = session.getTransaction();
trans.begin();

The above two statements can be replaced as

Transaction trans = session.beginTransaction();

Three Employee objects emp1, emp2 and emp3 are created and set some values. These objects are added to Set emps. emps is added to Dept object dept. The dept object, at runtime, adds its own values like deptName etc. to its own dept table and the other employeeId and employeeName etc. to employee table.

Observe the tables output.

image

Following is the Console screenshot.

One-to-Many Hibernate

Now let us write one more client program, Client2 to fetch the records of dept and employee tables through one dept object.

import java.util.Iterator;
import java.util.Set;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
 
public class RetrieveClient 
{
  public static void main(String args[])
  {
    Configuration c = new Configuration();
    c.configure("hibernate.cfg.xml");
 
    SessionFactory sf = c.buildSessionFactory();
    Session session = sf.openSession();
                                            // for fetching Transaction object is not required
    Object obj = session.get(Dept.class, new Integer(1234));
    Dept d1 = (Dept) obj;
    System.out.println(d1.getDeptId() + "  " + d1.getDeptName());
    		 
    Set mySet = d1.getEmployees();
    Iterator it = mySet.iterator();

    System.out.println("\nEmployee records:");
    while(it.hasNext())
    {
      Employee emp = (Employee)it.next();
      System.out.println(emp.getEmployeeId() + " " + emp.getEmployeeName()); 
    }
 
    session.close();
    System.out.println("Thank you, One To Many is Done");
    sf.close();
  }
}

One-to-Many Hibernate

Now let us write one more client program, DeleteClient to delete one record. When one Dept object is deleted, it’s associated all the Employee objects are also deleted.

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
 
public class DeleteClient 
{
  public static void main(String args[])
  {
    Configuration c = new Configuration();
    c.configure("hibernate.cfg.xml");
 
    SessionFactory sf = c.buildSessionFactory();
    Session s = sf.openSession();

    Dept d1 = (Dept) s.get(Dept.class, new Integer(1234));  	                  
                                               // better use load()
    Transaction tx = s.beginTransaction();     // instead of get().  Why?
    s.delete(d1);                              // refer separate notes on the differences of get() and load()
    tx.commit();
 
    s.close();

    System.out.println("One To Many deletion is over");
    sf.close();
  }
}

After executing the above deletion program, check the database, the record of 1234 of dept table and its associated records of employee table are deleted. This is the power of Hibernate. Is it so simple in JDBC?

Leave a Comment

Your email address will not be published.