Hibernate Parent Child Mapping Example
- Details
- Written by Nam Ha Minh
- Last Updated on 12 December 2023   |   Print Email
Through this tutorial, I will guide you how to implement a parent-child mapping using JPA annotations with Hibernate framework. A parent/child relationship is needed to represent nested, hierarchical structures like categories, as shown in the following picture:
As you can see, a category can have one or many children categories below it. And vice-versa, a category can have one or many parent categories above it – forming a nested, hierarchical structure. There’s no limit for the nested level.
So in this tutorial, you will learn how to use Hibernate framework to map a parent-child relationship for categories.
1. Design Database Table
Create the category table in the database with the following structure:
As you can see, the column parent_id is a foreign key that refers to the primary key column category_id of the table itself. That forms a parent-child relationship. You can execute the following MySQL script to create this table:
CREATE TABLE `category` ( `category_id` int(11) NOT NULL AUTO_INCREMENT, `name` varchar(128) NOT NULL, `parent_id` int(11) DEFAULT NULL, PRIMARY KEY (`category_id`), KEY `parent_id_key` (`parent_id`), CONSTRAINT `parent_id_fk` FOREIGN KEY (`parent_id`) REFERENCES `category` (`category_id`) );
Note that if a category with parent_id is null – meaning that the category has no parent – it’s become the top-level or root category.
2. Code Entity Class for Parent-Child Mapping
To map a parent-child relationship, the entity class should have a reference to its direct parent (one to one relationship) and a set of its children (one to many relationship) – as depicted in the following class diagram:
So write code for the entity class Category as follows:
package net.codejava; import java.util.*; import javax.persistence.*; @Entity @Table public class Category { @Id @Column(name = "category_id") @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; @Column(length = 64) private String name; @OneToOne @JoinColumn(name = "parent_id") private Category parent; @OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) private Set<Category> children = new HashSet<>(); public Category(String name, Category parent) { this.name = name; this.parent = parent; } public Category(String name) { this.name = name; } public Category() { } public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Category getParent() { return parent; } public void setParent(Category parent) { this.parent = parent; } public Set<Category> getChildren() { return children; } public void setChildren(Set<Category> children) { this.children = children; } public void addChild(Category children) { this.children.add(children); } }
We use @OneToOne annotation to refer a category its parent:
@OneToOne @JoinColumn(name = "parent_id") private Category parent;
And to refer a category to its children, we use the @OneToMany annotation:
@OneToMany(mappedBy = "parent", cascade = CascadeType.ALL) private Set<Category> children = new HashSet<>();
In this kind of parent/child relationship, the entity class has references to itself so it is also called self-referenced entity mapping.
3. Code Test Program for Parent-Child Relationship
Now, let’s write code to create the categories structure as shown above and then list all the categories recursively.
Below is the code snippet for persisting categories with parent-child mapping:
StandardServiceRegistry registry = new StandardServiceRegistryBuilder() .configure() .build(); SessionFactory factory = new MetadataSources(registry) .buildMetadata() .buildSessionFactory(); Session session = factory.openSession(); Category electronics = new Category("Electronics"); Category mobilePhones = new Category("Mobile phones", electronics); Category washingMachines = new Category("Washing machines", electronics); electronics.addChild(mobilePhones); electronics.addChild(washingMachines); Category iPhone = new Category("iPhone", mobilePhones); Category samsung = new Category("Samsung", mobilePhones); mobilePhones.addChild(iPhone); mobilePhones.addChild(samsung); Category galaxy = new Category("Galaxy", samsung); samsung.addChild(galaxy); session.save(electronics); session.close(); factory.close();
And below is code snippet for listing all categories from the database – print them in parent-child hierarchy structure:
private static void listCategories(Session session) { Category electronics = session.get(Category.class, 1); Set<Category> children = electronics.getChildren(); System.out.println(electronics.getName()); for (Category child : children) { System.out.println("--" + child.getName()); printChildren(child, 1); } } private static void printChildren(Category parent, int subLevel) { Set<Category> children = parent.getChildren(); for (Category child : children) { for (int i = 0; i <= subLevel; i++) System.out.print("--"); System.out.println(child.getName()); printChildren(child, subLevel + 1); } }
It will print the following nice output:
Conclusion
So that you’ve learned how to implement a parent-child relationship with Hibernate framework, or self-referenced entity mapping. It’s useful for nested structure like categories with parent and children.
You can also watch the video version of this tutorial and download the sample project code below. Or get the code examples on GitHub here.
Other Hibernate Tutorials:
- Java Hibernate JPA Annotations Tutorial for Beginners
- Hibernate Hello World Tutorial for Beginners with Eclipse and MySQL
- Hibernate One-to-Many Using Join Table XML Mapping Example
- Hibernate Many-to-Many Association with Extra Columns in Join Table Example
- Hibernate Enum Type Mapping Example
- Hibernate Binary Data and BLOB Mapping Example
- Hibernate Query Language (HQL) Example
- Java Hibernate Reverse Engineering Tutorial with Eclipse and MySQL
- Hibernate Basics - 3 ways to delete an entity from the datastore
- Hibernate Forward Engineering - Create Tables from Entity Classes
Comments
jakarta.persistence
An update will be nice...
@ManyToOne
@JoinColumn(name = "parent_id")
private Category parent;
Anyway it doesn't work for me. But thank you for the article)