Since we've already learned about the unidirectional @ManyToOne relationship, we can now move on to talking about what a bidirectional relationship is like, when using Hibernate.

The term “bidirectional” literally means “functioning in two directions”, which is the concept that we will apply in our relationships between two Java objects. When we have a bidirectional relationship between objects, it means that we are able to access Object A from Object B, and Object B from Object A.

We can apply this logic to our real world coding example that we saw in the last post. The example we will use is the relationship between an Employer and an Employee. Previously, we only defined a unidirectional relationship, so we could only access the Employer from the Employee object and not vice-versa.

Now let's take a look at how to transform our existing unidirectional relationship into a bidirectional one.

Bidirectional @OneToMany Relationship – Employer/Employee

The first step in transforming our unidirectional relationship into a bidirectional relationship is to add the missing reference from the Employer to the Employee.

One critical thing to remember here is that there's a difference between a reference from the One-to-Many side and the Many-to-One side.

When you traverse from the “Many” side to the “One” side, you only need to make reference to one object, which is why the Employee class holds a single reference to an Employer class via the private Employer employer instance variable.

However, when you traverse from the “One” to the “Many” side, you will need to hold a reference to MANY objects.

Does that make sense? Many-to-One equals one reference, One-to-Many equals many references.

So what will this look like? Well, it means that the Employer will need to hold many references to its Employees, and we accomplish this by storing them as a Collection.

In this example I will use a Set of Employee objects in my Employer class file like so:

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;
	private Set employees;

	@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;
	}

	@OneToMany(cascade=CascadeType.ALL, mappedBy="employer")
	public Set getEmployees()
	{
		return employees;
	}
	public void setEmployees(Set employees)
	{
		this.employees = employees;
	}
}

What you may have also noticed was that we added the @OneToMany annotation to the getEmployees() method. This is needed so that Hibernate understands that this is the second part of the relationship/link between the Employer and Employee.

So just like we have the @ManyToOne annotation in the Employee class, we also have the @OneToMany annotation in the Employer class… you see? Bidirectional!

Now, I haven't yet explained what that pesky mappedBy="employer" means…

Using the mappedBy Property on Bidirectional One-to-Many Relationship

The funny thing is that you don't actually need to use the mappedBy property, but your database will be quite a mess if you don't.

So I like to say that it's mandatory to use the mappedBy property when creating a bidirectional relationship in Hibernate. And yes, I did mean to refer to ALL bidirectional relationships with that previous statement.

The mappedBy property is what we use to tell Hibernate which variable we are using to represent the parent class in our child class.

If you were to look at the class definition for the child class (Employee) you will see that we have declared an instance variable called employer, which is what we used to establish our relationship. All we are doing here is we are telling the Employer class which variable the Employee class is using to create the relationship.

So! Since we declared the Employer variable with the name employer, this is what we need to put in the mappedBy property of the @OneToMany annotation.

For those of you who haven't already seen it, here's what the Employee class looks like (note that we haven't made any changes to this class when we had initially created our unidirectional relationship in the last post):

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;
	}
	@ManyToOne(cascade=CascadeType.ALL)
	public Employer getEmployer()
	{
		return employer;
	}
	public void setEmployer(Employer employer)
	{
		this.employer = employer;
	}
}

Putting our Bidirectional Relationship to Use

Okay, so now that we've created the blueprint for our bidirectional relationship, now we need to put in the supporting code to actually test this stuff out!

In the previous post we had created an EmployeeDao object which we used to save our employee1 and employee2 objects into the database in a unidirectional manner… but… now that we've changed our code around to use a bidirectional relationship, we need to change the way we persist our data.

As I mentioned, we previously used the EmployeeDao to persist our data, but now that we've switched to bidirectional we will need to use an EmployerDao to carry out our wishes! The EmployerDao will be identical to the EmployeeDao except that it will persist an Employer object. Here's what it looks like:

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.Employer;

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

  public void save (Employer employer)
  {
  	Session session = sessionFactory.getCurrentSession();

  	session.save(employer);
  }

}

Now the only missing piece is to show you how to actually persist data using this new bidirectional One-to-Many mapping.

I've set up the test code in a Controller class, I'll include all of the code for the sake of completion, but all you really need to be concerned with is how the code inside the test method works.

import java.util.HashSet;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import com.howtoprogramwithjava.example.dao.EmployerDao;
import com.howtoprogramwithjava.example.persistence.Employee;
import com.howtoprogramwithjava.example.persistence.Employer;

@Controller
public class HomeController
{
  @Autowired
  EmployerDao employerDao;

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

		Set employees = new HashSet();

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

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

		employer.setEmployees(employees);

		employerDao.save(employer);

		return "testPage";
	}
}

Inside of the test method is where all the magic happens.

What you need to know is that since we have a bidirectional relationship, this means we need to assign objects to EACH side of the relationship. This means that we need to populate both the employee.setEmployer() as well as the employer.setEmployees(). It's absolutely critical that this be done correctly.

To persist all the objects correctly you'll need to follow these generic steps:

  1. Instantiate/Load parent object
  2. Instantiate/Load child objects
  3. Set the parent object in the child objects
  4. Create a collection of child objects
  5. Set the collection of child objects on the parent
  6. Save the parent

Note: To observe best coding practices, the code I've put into this Controller class is usually best placed in a Service class, but to keep things as simple as possible for this tutorial I've just placed all the code directly into the Controller.

Alright! We're done! You now know how to create a One-to-Many bidirectional relationship with Hibernate. Congrats!

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.