Hibernate One-to-Many Mapping Example

In this tutorial, we will demonstrate how to set up a one-to-many mapping between two entities using Hibernate annotations. We will create an example with Department and Employee entities to illustrate this mapping and cover CRUD operations.

Prerequisites

  1. Java Development Kit (JDK) 11 or higher: Ensure JDK is installed and configured on your system.
  2. Integrated Development Environment (IDE): IntelliJ IDEA, Eclipse, or any other IDE.
  3. Maven: Ensure Maven is installed and configured on your system.

Step 1: Create a Maven Project

  1. Open your IDE and create a new Maven project.
  2. Update the pom.xml file to include Hibernate and other required dependencies.
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.example</groupId>
    <artifactId>hibernate-one-to-many-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.2.0.Final</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.7.30</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.7.30</version>
        </dependency>
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>1.4.200</version>
        </dependency>
    </dependencies>
</project>

Explanation

  • Hibernate Core Dependency: Includes the main Hibernate framework.
  • SLF4J Dependencies: Used for logging.
  • H2 Database Dependency: An in-memory database for testing purposes.

Step 2: Create Hibernate Configuration File

Create a file named hibernate.cfg.xml in the src/main/resources directory.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property>
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.url">jdbc:h2:mem:testdb</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="hibernate.show_sql">true</property>
        <property name="hibernate.format_sql">true</property>
    </session-factory>
</hibernate-configuration>

Explanation

  • Dialect: Specifies the SQL dialect (H2 in this case).
  • Connection Properties: Configure the JDBC connection to the H2 database.
  • hbm2ddl.auto: Automatically manages the database schema (update existing schema).
  • show_sql: Prints SQL statements to the console.
  • format_sql: Formats SQL statements.

Step 3: Create the Department Entity Class

Create a package named com.example.entity and a class named Department.

package com.example.entity;

import jakarta.persistence.*;
import java.util.HashSet;
import java.util.Set;

@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @OneToMany(mappedBy = "department", cascade = CascadeType.ALL, orphanRemoval = true)
    private Set<Employee> employees = new HashSet<>();

    public Department() {}

    public Department(String name) {
        this.name = name;
    }

    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 Set<Employee> getEmployees() {
        return employees;
    }

    public void setEmployees(Set<Employee> employees) {
        this.employees = employees;
    }

    public void addEmployee(Employee employee) {
        employees.add(employee);
        employee.setDepartment(this);
    }

    public void removeEmployee(Employee employee) {
        employees.remove(employee);
        employee.setDepartment(null);
    }

    @Override
    public String toString() {
        return "Department{id=" + id + ", name='" + name + '\'' + '}';
    }
}

Explanation

  • @Entity: Marks the class as an entity.
  • @Id: Marks the field as the primary key.
  • @GeneratedValue: Specifies the strategy for generating values for the primary key.
  • @OneToMany: Defines a one-to-many relationship with the Employee entity.
  • mappedBy: Specifies the field in the Employee entity that owns the relationship.
  • cascade: Specifies the cascade operations.
  • orphanRemoval: Specifies whether to remove orphaned entities.

Step 4: Create the Employee Entity Class

Create a class named Employee in the same package.

package com.example.entity;

import jakarta.persistence.*;

@Entity
public class Employee {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String name;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "department_id")
    private Department department;

    public Employee() {}

    public Employee(String name) {
        this.name = name;
    }

    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 Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    @Override
    public String toString() {
        return "Employee{id=" + id + ", name='" + name + '\'' + '}';
    }
}

Explanation

  • @Entity: Marks the class as an entity.
  • @Id: Marks the field as the primary key.
  • @GeneratedValue: Specifies the strategy for generating values for the primary key.
  • @ManyToOne: Defines a many-to-one relationship with the Department entity.
  • @JoinColumn: Specifies the foreign key column.

Step 5: Create a Hibernate Utility Class

Create a package named com.example.util and a class named HibernateUtil.

package com.example.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {
    private static SessionFactory sessionFactory;

    static {
        try {
            Configuration configuration = new Configuration().configure();
            ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                    .applySettings(configuration.getProperties()).build();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
        } catch (Throwable ex) {
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }
}

Explanation

  • Configuration: Loads Hibernate configuration from hibernate.cfg.xml.
  • ServiceRegistry: Builds the service registry from the configuration settings.
  • SessionFactory: Provides sessions to interact with the database.

Step 6: Create Main Class

Create a package named com.example and a class named Main.

package com.example;

import com.example.entity.Department;
import com.example.entity.Employee;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class Main {
    public static void main(String[] args) {
        // Initialize session and transaction
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction transaction = session.beginTransaction();

        // Create department
        Department department = new Department("IT");

        // Create employees
        Employee employee1 = new Employee("John Doe");
        Employee employee2 = new Employee("Jane Doe");

        // Add employees to department
        department.addEmployee(employee1);
        department.addEmployee(employee2);

        // Save department (this will also save employees due to cascade)
        session.save(department);
        transaction.commit();
        session.close();

        // Retrieve and display department
        session = HibernateUtil.getSessionFactory().openSession();
        Department retrievedDepartment = session.get(Department.class, department.getId());
        System.out.println("Retrieved Department: " + retrievedDepartment);
        System.out.println("Employees: " + retrievedDepartment.getEmployees

());
        session.close();

        // Update an employee
        session = HibernateUtil.getSessionFactory().openSession();
        transaction = session.beginTransaction();
        Employee employeeToUpdate = session.get(Employee.class, employee1.getId());
        employeeToUpdate.setName("John Smith");
        session.update(employeeToUpdate);
        transaction.commit();
        session.close();

        // Delete an employee
        session = HibernateUtil.getSessionFactory().openSession();
        transaction = session.beginTransaction();
        Department departmentToUpdate = session.get(Department.class, department.getId());
        Employee employeeToDelete = session.get(Employee.class, employee2.getId());
        departmentToUpdate.removeEmployee(employeeToDelete);
        session.delete(employeeToDelete);
        transaction.commit();
        session.close();

        // Retrieve and display updated department
        session = HibernateUtil.getSessionFactory().openSession();
        Department updatedDepartment = session.get(Department.class, department.getId());
        System.out.println("Updated Department: " + updatedDepartment);
        System.out.println("Employees: " + updatedDepartment.getEmployees());
        session.close();

        // Close the SessionFactory
        HibernateUtil.getSessionFactory().close();
    }
}

Explanation

  • Session: Opens a session to interact with the database.
  • Transaction: Begins and commits a transaction for database operations.
  • Save: Persists the entity to the database.
  • Retrieve: Fetches the entity from the database using its ID.
  • Update: Updates the entity in the database.
  • Delete: Removes the entity from the database.

Step 7: Run the Application

  1. Run the Main class.
  2. The output in the console should be:
Hibernate: create table Department (id bigint generated by default as identity, name varchar(255), primary key (id))
Hibernate: create table Employee (id bigint generated by default as identity, department_id bigint, name varchar(255), primary key (id))
Hibernate: alter table Employee add constraint FKk19gk3d8xlt8afm6u7g4s7hn6 foreign key (department_id) references Department
Hibernate: insert into Department (name) values (?)
Hibernate: insert into Employee (department_id, name) values (?, ?)
Hibernate: insert into Employee (department_id, name) values (?, ?)
Hibernate: select departmen0_.id as id1_0_0_, departmen0_.name as name2_0_0_ from Department departmen0_ where departmen0_.id=?
Hibernate: select employees0_.department_id as departme3_1_0_, employees0_.id as id1_1_0_, employees0_.id as id1_1_1_, employees0_.department_id as departme3_1_1_, employees0_.name as name2_1_1_ from Employee employees0_ where employees0_.department_id=?
Retrieved Department: Department{id=1, name='IT'}
Employees: [Employee{id=1, name='John Doe'}, Employee{id=2, name='Jane Doe'}]
Hibernate: select employee0_.id as id1_1_0_, employee0_.department_id as departme3_1_0_, employee0_.name as name2_1_0_ from Employee employee0_ where employee0_.id=?
Hibernate: update Employee set department_id=?, name=? where id=?
Hibernate: select departmen0_.id as id1_0_0_, departmen0_.name as name2_0_0_ from Department departmen0_ where departmen0_.id=?
Hibernate: select employees0_.department_id as departme3_1_0_, employees0_.id as id1_1_0_, employees0_.id as id1_1_1_, employees0_.department_id as departme3_1_1_, employees0_.name as name2_1_1_ from Employee employees0_ where employees0_.department_id=?
Hibernate: select employee0_.id as id1_1_0_, employee0_.department_id as departme3_1_0_, employee0_.name as name2_1_0_ from Employee employee0_ where employee0_.id=?
Hibernate: delete from Employee where id=?
Hibernate: update Employee set department_id=? where id=?
Hibernate: select departmen0_.id as id1_0_0_, departmen0_.name as name2_0_0_ from Department departmen0_ where departmen0_.id=?
Hibernate: select employees0_.department_id as departme3_1_0_, employees0_.id as id1_1_0_, employees0_.id as id1_1_1_, employees0_.department_id as departme3_1_1_, employees0_.name as name2_1_1_ from Employee employees0_ where employees0_.department_id=?
Updated Department: Department{id=1, name='IT'}
Employees: [Employee{id=1, name='John Smith'}]

Conclusion

You have successfully created an example using Hibernate to demonstrate a one-to-many mapping with annotations. This tutorial covered setting up a Maven project, configuring Hibernate, creating entity classes with a one-to-many relationship, and performing CRUD operations.


Comments