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:
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 @OneToOneannotation to refer a category its 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:ConclusionSo 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.
Nam Ha Minh is certified Java programmer (SCJP and SCWCD). He began programming with Java back in the days of Java 1.4 and has been passionate about it ever since. You can connect with him on Facebook and watch his Java videos on YouTube.
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)