Thursday 3 April 2008

Hibernate Cascading for Save and Delete

To explain the cascading of save and delete lets take an example of Employee, Company and Acccount.
Many employees can belong to same company.
An employee can have many accounts with it.
Company.java
package model;
import javax.persistence.*;
import javax.persistence.Entity;
import java.util.List;
@Entity
public class Company {
@Id
private long id;
private String name;
@OneToMany(mappedBy = "company")
private List employees;
public List getEmployees() {
return employees;
}
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 void setEmployees(List employees) {
this.employees = employees;
}
}
Employee.java
package model;
import org.hibernate.annotations.*;
import javax.persistence.*;
import javax.persistence.Entity;
import java.util.List;
import java.util.ArrayList;
@Entity
public class Employee {
@Id
private long id;
private String name;
@ManyToOne
@JoinColumn(name = "company_id")
@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE})

private Company company;
@OneToMany(mappedBy = "employee")
@Cascade({org.hibernate.annotations.CascadeType.ALL})

private List accounts;
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
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 List getAccounts() {
return accounts;
}
public void setAccounts(List accounts) {
this.accounts = accounts;
}
public void addAccount(Account account){
if(getAccounts()==null){
accounts=new ArrayList();
}
getAccounts().add(account);
}
}
Account.java
package model;
import javax.persistence.*;
import javax.persistence.Entity;
@Entity
public class Account {
@Id
private long id;
private String name;
@ManyToOne
private Employee employee;

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 Employee getEmployee() {
return employee;
}
public void setEmployee(Employee employee) {
this.employee = employee;
}
}
Save Cascading
Cascading Save is a recursive process that could be described as "walking the object graph". The general algorithm for save goes:
· Prior to saving a bean we save its ManyToOne associations (And appropriate OneToOnes)
· Then we save the bean itself
· Then we save any OneToMany, ManyToMany (And appropriate OneToOnes)
Note: OneToOnes will occur prior and post saving the bean depending on whether the OneToOne owns the foreign key or not. If that doesn't make sense don't worry too much.
Employee employee=new Employee();
………………………..
//employee is belonging to one company.
//employee has two accounts (assume two).
Session.save(employee);
In this example
Session.save(employee) will do the following things.
Prior to saving the employee, company will be saved.
After the company is saved the employee will be saved.
After the employee is saved the accounts are saved.
A "Relational" way of describing this is that we go "up the imported foreign keys", then save the bean, then go "down the exported foreign keys".
Perhaps another way of thinking about this is to take the example where every object is new and will need to be inserted.
Before we save the employee, we need company’s id, hence company is saved before employee.
Once the company is saved, employee is saved.
Accounts need employee_id before it is saved.
Hence once, employee is saved, accounts are also saved.
Delete Cascading
Delete cascading is very similar except the order is reversed.
1 Prior to deleting a bean we delete its OneToMany, ManyToMany (And appropriate OneToOnes) associations
2 Then we delete the bean itself
3 Then we delte any ManyToOne (And appropriate OneToOnes)

Here is the test class which uses these three classes to create record in database.
package test;
import org.hibernate.SessionFactory;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import model.Employee;
import model.Company;
import model.Account;
public class MyTest {
public static void main(String[] args) {
Resource resource=new ClassPathResource("applicationContext.xml");
BeanFactory factory=new XmlBeanFactory(resource);
SessionFactory sessionFactory= (SessionFactory) factory.getBean("sessionFactory");
Session session=sessionFactory.openSession();
Transaction transaction=session.beginTransaction();
Employee employee=new Employee();
employee.setId(1);
employee.setName("abcd");
Company company=new Company();
company.setId(1);
company.setName("ABCDEFGH");
employee.setCompany(company);
Account account1=new Account();
account1.setId(1);
account1.setName("HDFC");
account1.setEmployee(employee);
Account accoutn2=new Account();
accoutn2.setId(2);
accoutn2.setName("ICICI");
accoutn2.setEmployee(employee);
employee.addAccount(account1);
employee.addAccount(accoutn2);
session.save(employee);
transaction.commit();
session.flush();
session.close();
}
}

No comments: