Sunday, 25 December 2022

Hibernate 6: @ManyToOne: Many to one mapping example

Many to One association establishes a relationship between a child entity and a parent.

 

For example, an employee can have one or more bank accounts. That means many bank accounts are mapped to one employee.

 

Example

@Entity
@Table(name = "employees")
public class Employee {
	@Id
	private int id;

	private String firstName;

	private String lastName;

	.........
	.........
}

@Entity
@Table(name = "bank_account_details")
public class BankAccount {

	@Id
	private int id;

	private String accountNumber;

	private String branch;

	private String ifscCode;

	private String address;

	@ManyToOne
	@JoinColumn(name = "employee_id", foreignKey = @ForeignKey(name = "bank_acc_emp_id_fk"))
	private Employee employee;

	..........
	..........
}

 

Above snippet adds

 

a.   a column ‘employee_id’ is added to bank_account_details.

b.   employee_id is a foreign key that maps to the id of employees table.

 

Above snippet generates following DDL.

create table bank_account_details (
	id integer not null, 
	accountNumber varchar(255), 
	address varchar(255), 
	branch varchar(255), 
	ifscCode varchar(255), 
	employee_id integer, 
	primary key (id)
)

create table employees (
	id integer not null, 
	firstName varchar(255), 
	lastName varchar(255), 
	primary key (id)
)

alter table if exists bank_account_details add constraint bank_acc_emp_id_fk foreign key (employee_id) references employees


Find the below working application.

 

Step 1: Create new maven project ‘hibernate-many-to-one-mapping’.

 

Step 2: Update pom.xml with maven dependencies.

 

pom.xml

<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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<groupId>com.sample.app</groupId>
	<artifactId>hibernate-many-to-one-mapping</artifactId>
	<version>1</version>

	<properties>
		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

		<java.version>15</java.version>
		<maven.compiler.source>${java.version}</maven.compiler.source>
		<maven.compiler.target>${java.version}</maven.compiler.target>

	</properties>

	<dependencies>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<version>42.4.1</version>
		</dependency>

		<dependency>
			<groupId>org.hibernate</groupId>
			<artifactId>hibernate-core</artifactId>
			<version>6.1.2.Final</version>
		</dependency>


	</dependencies>
</project>

Step 3: Define entity classes.

 

Employee.java

package com.sample.app.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;

@Entity
@Table(name = "employees")
public class Employee {
	@Id
	private int id;

	private String firstName;

	private String lastName;

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public String getFirstName() {
		return firstName;
	}

	public void setFirstName(String firstName) {
		this.firstName = firstName;
	}

	public String getLastName() {
		return lastName;
	}

	public void setLastName(String lastName) {
		this.lastName = lastName;
	}

	@Override
	public String toString() {
		return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + "]";
	}

}

BankAccount.java

package com.sample.app.entity;

import jakarta.persistence.Entity;
import jakarta.persistence.ForeignKey;
import jakarta.persistence.Id;
import jakarta.persistence.JoinColumn;
import jakarta.persistence.ManyToOne;
import jakarta.persistence.Table;

@Entity
@Table(name = "bank_account_details")
public class BankAccount {

	@Id
	private int id;

	private String accountNumber;

	private String branch;

	private String ifscCode;

	private String address;

	@ManyToOne
	@JoinColumn(name = "employee_id", foreignKey = @ForeignKey(name = "bank_acc_emp_id_fk"))
	private Employee employee;

	public String getAccountNumber() {
		return accountNumber;
	}

	public void setAccountNumber(String accountNumber) {
		this.accountNumber = accountNumber;
	}

	public String getBranch() {
		return branch;
	}

	public void setBranch(String branch) {
		this.branch = branch;
	}

	public String getIfscCode() {
		return ifscCode;
	}

	public void setIfscCode(String ifscCode) {
		this.ifscCode = ifscCode;
	}

	public String getAddress() {
		return address;
	}

	public void setAddress(String address) {
		this.address = address;
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
	}

	public Employee getEmployee() {
		return employee;
	}

	public void setEmployee(Employee employee) {
		this.employee = employee;
	}

	@Override
	public String toString() {
		return "BankAccount [id=" + id + ", accountNumber=" + accountNumber + ", branch=" + branch + ", ifscCode="
				+ ifscCode + ", address=" + address + ", employee=" + employee + "]";
	}

}

Step 4: Create hibernate.cfg.xml file under src/main/resources folder.

 

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

	<session-factory>

		<!-- Database Connection settings -->
		<property name="connection.driver_class">org.postgresql.Driver</property>
		<property name="connection.url">jdbc:postgresql://127.0.0.1:5432/test</property>
		<property name="connection.username">postgres</property>
		<property name="connection.password">postgres</property>

		<!-- Enable the logging of all the generated SQL statements to the console -->
		<property name="show_sql">true</property>

		<!-- Format the generated SQL statement to make it more readable, -->
		<property name="format_sql">false</property>

		<!-- Hibernate will put comments inside all generated SQL statements to 
			hint what’s the generated SQL trying to do -->
		<property name="use_sql_comments">false</property>

		<!-- This property makes Hibernate generate the appropriate SQL for the 
			chosen database. -->
		<property name="dialect">org.hibernate.dialect.PostgreSQLDialect</property>

		<!-- Drop and re-create the database schema on startup -->
		<property name="hbm2ddl.auto">create</property>

		<!-- mappings for annotated classes -->
		<mapping class="com.sample.app.entity.Employee" />
		<mapping class="com.sample.app.entity.BankAccount" />

	</session-factory>

</hibernate-configuration>

Step 5: Define main application class.

 

App.java

package com.sample.app;

import java.util.List;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import com.sample.app.entity.BankAccount;
import com.sample.app.entity.Employee;

import jakarta.persistence.criteria.CriteriaBuilder;
import jakarta.persistence.criteria.CriteriaQuery;

public class App {
	private static SessionFactory sessionFactory = buildSessionFactory();

	private static <T> List<T> loadAllData(Class<T> clazz, Session session) {
		final CriteriaBuilder builder = session.getCriteriaBuilder();
		final CriteriaQuery<T> criteria = builder.createQuery(clazz);
		criteria.from(clazz);
		return session.createQuery(criteria).getResultList();
	}

	private static SessionFactory buildSessionFactory() {
		try {
			if (sessionFactory == null) {
				StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder()
						.configure("hibernate.cfg.xml").build();

				Metadata metaData = new MetadataSources(standardRegistry).getMetadataBuilder().build();

				sessionFactory = metaData.getSessionFactoryBuilder().build();
			}
			return sessionFactory;
		} catch (Throwable ex) {
			throw new ExceptionInInitializerError(ex);
		}
	}

	public static void main(String args[]) {

		try (Session session = sessionFactory.openSession()) {
			session.beginTransaction();

			Employee emp1 = new Employee();
			emp1.setFirstName("Krishna");
			emp1.setLastName("Gurram");
			emp1.setId(1);

			session.persist(emp1);
			session.flush();
			session.getTransaction().commit();

			session.beginTransaction();

			Employee emp = session.find(Employee.class, 1);

			BankAccount account1 = new BankAccount();
			account1.setAccountNumber("number1");
			account1.setAddress("address1");
			account1.setBranch("branch1");
			account1.setId(1);
			account1.setIfscCode("ifsc1");
			account1.setEmployee(emp);

			BankAccount account2 = new BankAccount();
			account2.setAccountNumber("number2");
			account2.setAddress("address2");
			account2.setBranch("branch2");
			account2.setId(2);
			account2.setIfscCode("ifsc2");
			account2.setEmployee(emp);

			session.persist(account1);
			session.persist(account2);

			session.getTransaction().commit();

			List<Employee> emps = loadAllData(Employee.class, session);
			for (Employee empTemp : emps) {
				System.out.println(empTemp);
			}

			List<BankAccount> bankAccounts = loadAllData(BankAccount.class, session);
			for (BankAccount bankAccount : bankAccounts) {
				System.out.println(bankAccount);
			}

		}

	}
}

Total project structure looks like below.


Run App.java, you will see below messages in the console.

Sep 06, 2022 10:20:00 AM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.1.2.Final
Sep 06, 2022 10:20:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Sep 06, 2022 10:20:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.postgresql.Driver
Sep 06, 2022 10:20:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:postgresql://127.0.0.1:5432/test]
Sep 06, 2022 10:20:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {password=****, user=postgres}
Sep 06, 2022 10:20:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Sep 06, 2022 10:20:00 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 20 (min=1)
Sep 06, 2022 10:20:00 AM org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl logSelectedDialect
INFO: HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
Hibernate: alter table if exists bank_account_details drop constraint if exists bank_acc_emp_id_fk
Sep 06, 2022 10:20:01 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@36327cec] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Sep 06, 2022 10:20:01 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Sep 06, 2022 10:20:01 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: relation "bank_account_details" does not exist, skipping
Hibernate: drop table if exists bank_account_details cascade
Sep 06, 2022 10:20:01 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Sep 06, 2022 10:20:01 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: table "bank_account_details" does not exist, skipping
Hibernate: drop table if exists employees cascade
Sep 06, 2022 10:20:01 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Sep 06, 2022 10:20:01 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: table "employees" does not exist, skipping
Hibernate: create table bank_account_details (id integer not null, accountNumber varchar(255), address varchar(255), branch varchar(255), ifscCode varchar(255), employee_id integer, primary key (id))
Sep 06, 2022 10:20:01 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@e146f93] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode.
Hibernate: create table employees (id integer not null, firstName varchar(255), lastName varchar(255), primary key (id))
Hibernate: alter table if exists bank_account_details add constraint bank_acc_emp_id_fk foreign key (employee_id) references employees
Sep 06, 2022 10:20:01 AM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService
INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
Hibernate: insert into employees (firstName, lastName, id) values (?, ?, ?)
Hibernate: insert into bank_account_details (accountNumber, address, branch, employee_id, ifscCode, id) values (?, ?, ?, ?, ?, ?)
Hibernate: insert into bank_account_details (accountNumber, address, branch, employee_id, ifscCode, id) values (?, ?, ?, ?, ?, ?)
Hibernate: select e1_0.id,e1_0.firstName,e1_0.lastName from employees e1_0
Employee [id=1, firstName=Krishna, lastName=Gurram]
Hibernate: select b1_0.id,b1_0.accountNumber,b1_0.address,b1_0.branch,b1_0.employee_id,b1_0.ifscCode from bank_account_details b1_0
BankAccount [id=1, accountNumber=number1, branch=branch1, ifscCode=ifsc1, address=address1, employee=Employee [id=1, firstName=Krishna, lastName=Gurram]]
BankAccount [id=2, accountNumber=number2, branch=branch2, ifscCode=ifsc2, address=address2, employee=Employee [id=1, firstName=Krishna, lastName=Gurram]]

 

Query the database to get the DDLs.

test=# \d employees;
                      Table "public.employees"
  Column   |          Type          | Collation | Nullable | Default 
-----------+------------------------+-----------+----------+---------
 id        | integer                |           | not null | 
 firstname | character varying(255) |           |          | 
 lastname  | character varying(255) |           |          | 
Indexes:
    "employees_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "bank_account_details" CONSTRAINT "bank_acc_emp_id_fk" FOREIGN KEY (employee_id) REFERENCES employees(id)

test=# 
test=# 
test=# \d bank_account_details;
                   Table "public.bank_account_details"
    Column     |          Type          | Collation | Nullable | Default 
---------------+------------------------+-----------+----------+---------
 id            | integer                |           | not null | 
 accountnumber | character varying(255) |           |          | 
 address       | character varying(255) |           |          | 
 branch        | character varying(255) |           |          | 
 ifsccode      | character varying(255) |           |          | 
 employee_id   | integer                |           |          | 
Indexes:
    "bank_account_details_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "bank_acc_emp_id_fk" FOREIGN KEY (employee_id) REFERENCES employees(id)

 

Query the database to get the content of employees and bank_account_details table.

test=# SELECT * FROM employees;
 id | firstname | lastname 
----+-----------+----------
  1 | Krishna   | Gurram
(1 row)

test=# 
test=# 
test=# 
test=# SELECT * FROM bank_account_details;
 id | accountnumber | address  | branch  | ifsccode | employee_id 
----+---------------+----------+---------+----------+-------------
  1 | number1       | address1 | branch1 | ifsc1    |           1
  2 | number2       | address2 | branch2 | ifsc2    |           1
(2 rows)

 

You can download this application from this link.



  

Previous                                                    Next                                                    Home

No comments:

Post a Comment