In the past we have learned about database relationships, specifically the One-to-Many as well as the Many-to-Many and One-to-One and that was all good, great and grand…

But now I want to talk about how to create those same relationships inside of Hibernate.

Specifically, I want to focus on the One-to-Many relationship in Hibernate and how we go about mapping it out in our Java objects.

But before we do, a word on unidirectional and bidirectional relationships.

Unidirectional vs Bidirectional

In Hibernate, it's possible to map all three relationships that are available in a standard database, these include:

  • One-to-One
  • One-to-Many
  • Many-to-Many

But what Hibernate also includes is the ability to make EACH of those relationships either unidirectional or bidirectional.

This means that we can have a unidirectional One-to-One and a bidirectional One-to-One mapping, as well as a unidirectional One-to-Many and a bidirectional One-to-Many, as well as a unidirectional Many-to-Many and a bidirectional Many-to-Many relationship.

That's a lot of relationships!

So what exactly are unidirectional and bidirectional relationships?

It all comes down to Java objects.

Let's say for example that we have a One-to-Many relationship between Employer and Employee. For any one Employer there can be Many Employees and for any given Employee there can be only one Employer.

If we convert the statement above into Java objects, here's what that would look like:

Employer.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Employer
{
	private Long id;
	private String employerName;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	public Long getId()
	{
		return id;
	}
	public void setId(Long id)
	{
		this.id = id;
	}
	public String getEmployerName()
	{
		return employerName;
	}
	public void setEmployerName(String employerName)
	{
		this.employerName = employerName;
	}
}

Employee.java

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

@Entity
public class Employee
{
	private Long id;
	private String employeeName;
	private Employer employer;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	public Long getId()
	{
		return id;
	}
	public void setId(Long id)
	{
		this.id = id;
	}
	public String getEmployeeName()
	{
		return employeeName;
	}
	public void setEmployeeName(String employeeName)
	{
		this.employeeName = employeeName;
	}

	public Employer getEmployer()
	{
		return employer;
	}
	public void setEmployer(Employer employer)
	{
		this.employer = employer;
	}
}

Okay, so, now we have two Java objects which are enabled as Hibernate Entity objects (via the @Entity annotation). Plus we've got all the appropriate mappings for the columns (i.e. @Id and @GeneratedValue for the primary keys).

Also you should note that there's one key difference between these two objects… the Employee object defines the instance variable private Employer employer as well as the appropriate getters and setters.

This is the key to mapping out a unidirectional relationship.

If we were to instantiate an instance of both of these objects we would be able to determine which Employer an Employee works for (via employee.getEmployer()) but we wouldn't be able to determine which Employees work for a given Employer (as we have no employer.getEmployees() method).

This is the meaning of a unidirectional relationship. We can only “look” at the relationship in one way.

Now, if we wanted to make this relationship a bidirectional one, we would need to add the aforementioned employer.getEmployees() method… but I don't want to focus on bidirectional relationships just yet.

Parent and Child Tables

Alright, so you have an idea of the difference between a unidirectional and bidirectional relationship. The reason why it's important to understand the difference between the two is because it affects the way we will map out our code.

Given that we're focusing on the unidirectional aspect of the relationship, this means that we are only concerned with mapping the Employer instance variable within the Employee object.

As with all Hibernate related functionality, we will need to use an annotation to tell Hibernate how we'd like to map out our relationship.

But before I discuss those details we need to figure out one last concept… parent and child tables.

With a One-to-Many relationship, the child table is the one that houses the foreign key. So in our example, the foreign key will be placed into the Employee table. This is just the way it works with a One-to-Many relationship, the foreign key is always in the “Many” side of the relationship.

Now that we've isolated which is the child table (employee) and which is the parent table (employer) we can go a little deeper into the Hibernate mapping annotations.

@OneToMany vs @ManyToOne

Note that there are two different annotations for mapping a One-to-Many relationship in Hibernate:

  • @OneToMany
  • @ManyToOne

The reason that there are two different annotations is that we need to be able to tell Hibernate which object is the child/many part of the relationship and which object is the parent/one side of the relationship.

We are able to tell Hibernate which object is the parent object by assigning the @OneToMany annotation to the appropriate getter method… and of course we are able to tell Hibernate which object is the child object by assigning the @ManyToOne annotation to the appropriate getter method.

Now, keeping in mind that we're only concerned with the unidirectional relationship at the moment, I need to let you in on a secret. To properly map a unidirectional One-to-Many relationship, you only need to use the @ManyToOne annotation. This may seem a bit counter-intuitive, but that's how Hibernate works. You need to map the child/many side of the relationship and only the child/many side.

This fact works nicely with the example classes that I've outlined above, let's take a look at what changes we'll need to make to the child class (Employee) in order to enable Hibernate's relationship functionality:

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;

@Entity
public class Employee
{
	private Long id;
	private String employeeName;
	private Employer employer;

	@Id
	@GeneratedValue(strategy=GenerationType.AUTO)
	public Long getId()
	{
		return id;
	}
	public void setId(Long id)
	{
		this.id = id;
	}
	public String getEmployeeName()
	{
		return employeeName;
	}
	public void setEmployeeName(String employeeName)
	{
		this.employeeName = employeeName;
	}

    // HERE IS THE NEW ANNOTATION CODE WE'VE ADDED
    @ManyToOne(cascade=CascadeType.ALL)
	public Employer getEmployer()
	{
		return employer;
	}
	public void setEmployer(Employer employer)
	{
		this.employer = employer;
	}
}

You'll notice that all the code is the same except for the addition of the @ManyToOne annotation.

We place this annotation at the method level on the getter method for the object that we'd like to join with. Since we're joining to the Employer class, we put the annotation above the getEmployer() method.

One other thing to note is the cascade that we have assigned inside the annotation.

Cascades in Hibernate

The concept of cascading is pretty straight-forward and it deals with keeping the data in a nice organized state.

Let's say for example that we have inserted a couple of employers and three employees into our database. It might look something like this:

[table caption=”Employer Table” class=”table table-bordered” style=”width: 13em”] id[attr style=”background-color: #DDD”], employer_name[attr style=”background-color: #DDD”] 1, Employer 1
2, Employer 2[/table] [table caption=”Employee Table” class=”table table-bordered” style=”width: 21em”] id[attr style=”background-color: #DDD”], employee_name[attr style=”background-color: #DDD”], employer_id[attr style=”background-color: #DDD”] 1, Trevor Page, 1
2, John Doe, 1
3, Jane Doe, 2[/table]

Here we have two employees who are assigned to Employer 1, and one employee who is assigned to Employer 2.

What would happen if Employer 1 went out of business? All of the employees would likely be let go and wouldn't work at Employer 1 anymore. This is a fact that can be automatically “handled” by Hibernate. It's called a cascade delete.

When someone deletes Employer 1, Hibernate can be told (via cascading rules) to automatically delete any child rows that point to Employer 1. So when Employer 1 is delete, so will the employees “Trevor Page” and “John Doe” as they are associated with Employer 1.

The same concept is applied to inserting new values into the database via Hibernate.

In the example code above, we only assign a relationship to the child object via the @ManyToOne() annotation. This means that if we perform an insert on the child row, Hibernate will automatically create the parent row based on where the child row is pointing.

Let's take a look at this as a Java example. I've gone ahead and created a basic Controller that will perform the insertion of the records:

@Controller
public class HomeController
{
  @Autowired
  EmployeeDao employeeDao;

	@RequestMapping("test")
	public String test (ModelMap model)
	{
		Employer employer = new Employer();
		employer.setEmployerName("Employer 1");

		Employee employee1 = new Employee();
		employee1.setEmployeeName("Trevor Page");
		employee1.setEmployer(employer);

		Employee employee2 = new Employee();
		employee2.setEmployeeName("John Doe");
		employee2.setEmployer(employer);

	  employeeDao.save(employee1);
	  employeeDao.save(employee2);
		return "testPage";
	}
}

The main things to concern yourself with in the code above is everything inside of the test() method. I've included all of this code for the sake of completion, but I don't want you to get bogged down in the details outside of the test method.

The important things to note in the code above are that we're actually creating Java objects just like we would if we weren't using Hibernate. We instantiate instances of the Employer object as well as two Employee objects. After setting the names of both the employer and employees, we take one critical step in this process… we set the instance of the Employer object inside of each of the Employee objects.

The process of assigning the employer to the employees is critical, and if you think about it, it makes sense. We do the same thing in the database table right? We have an employer_id column inside of the employee table! So we're really just mimicking the database layout inside of our Java code… easy peasy!

Once we have done this, we invoke the save() method on the EmployeeDao object for each of our Employee objects. So the question is, what does the employeeDao.save() method do? I'll show you:

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.howtoprogramwithjava.example.persistence.Employee;

@Transactional
@Repository
public class EmployeeDao
{
  @Autowired
  SessionFactory sessionFactory;

  public void save (Employee employee)
  {
  	Session session = sessionFactory.getCurrentSession();

  	session.save(employee);
  }

}

All the EmployeeDao does is just grab the session and save the object.

Once this session.save(employee) method is invoked, this is where hibernate will try to insert the actual employee into the database. It will realize that there's a relationship set and will also realize that the parent row hasn't been inserted yet, so it will first insert the parent “employer” row, then it will insert the child “employee” row as expected.

If the appropriate “employer” row already exists in the database, then it will just insert the child row and assign the appropriate foreign key to the child row.

Done and done! So there you have it, you now know how to create a One-to-many relationship with the Hibernate framework and actually create and insert the data via Java code. Very powerful stuff.

As always, if you want to be on the cutting edge of these Java tutorials and receive updates on when I'm putting on free webinars and doing give-aways please join my mailing list by putting in your email address in the popup below. When you do you'll instantly receive one free gift from me (and plenty more in the future). I look forward to seeing you again soon!

Free Java Beginners Course

Start learning how to code today with our free beginners course. Learn more.