Monday, 26 December 2022

Hibernate 6: Unidirectional one to one association

In a one-to-one relationship, each row in one database table is linked to one and only one other row in another table.

 

For example, there is one to one relationship between employee and employee_details.

 

Types of One to One association

There are two types of one to one association.

a.   Unidirectional one to one association

b.   Bidirectional one to one association

 

Unidirectional one to one association

@Entity
@Table(name = "employee_details")
public class EmployeeDetails {

	@Id
	private int id;

	private String departmentName;

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

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

	private String name;

	@OneToOne
	@JoinColumn(name = "employee_details_id")
	private EmployeeDetails employeeDetails;

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

Above snippet generates below DDL.

create table employee (
       id integer not null,
        name varchar(255),
        employee_details_id integer,
        primary key (id)
    )

    create table employee_details (
       id integer not null,
        departmentName varchar(255),
        primary key (id)
    )

     alter table if exists employee 
       add constraint FKsg6w2kdo2j1t3wt0vxta131it 
       foreign key (employee_details_id) 
       references employee_details

Find the below working application.

 

Step 1: Create new maven project ‘hibernate-uni-directional-one-to-one’.

 

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-uni-directional-one-to-one</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.

 

EmployeeDetails.java

package com.sample.app.entity;

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

@Entity
@Table(name = "employee_details")
public class EmployeeDetails {

	@Id
	private int id;

	private String departmentName;

	public EmployeeDetails() {
	}

	public EmployeeDetails(int id, String departmentName) {
		this.id = id;
		this.departmentName = departmentName;
	}

	public int getId() {
		return id;
	}

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

	public String getDepartmentName() {
		return departmentName;
	}

	public void setDepartmentName(String departmentName) {
		this.departmentName = departmentName;
	}

	@Override
	public String toString() {
		return "EmployeeDetails [id=" + id + ", departmentName=" + departmentName + "]";
	}

}

Employee.java

package com.sample.app.entity;

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

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

	private String name;

	@OneToOne
	@JoinColumn(name = "employee_details_id")
	private EmployeeDetails employeeDetails;
	
	public Employee() {}

	public Employee(int id, String name, EmployeeDetails employeeDetails) {
		this.id = id;
		this.name = name;
		this.employeeDetails = employeeDetails;
	}

	public int getId() {
		return id;
	}

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

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public EmployeeDetails getEmployeeDetails() {
		return employeeDetails;
	}

	public void setEmployeeDetails(EmployeeDetails employeeDetails) {
		this.employeeDetails = employeeDetails;
	}

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

}

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">true</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.EmployeeDetails" />

	</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.Employee;
import com.sample.app.entity.EmployeeDetails;

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()) {

			EmployeeDetails empDetails1 = new EmployeeDetails(123, "Aerospace");
			session.beginTransaction();
			session.persist(empDetails1);
			session.flush();
			session.getTransaction().commit();

			EmployeeDetails persistedEmpDetails = session.find(EmployeeDetails.class, 123);
			Employee emp = new Employee(1, "Krishna", persistedEmpDetails);

			session.beginTransaction();
			session.persist(emp);
			session.flush();
			session.getTransaction().commit();

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

		}

	}
}

Total project structure looks like below.




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

Sep 11, 2022 11:31:20 AM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.1.2.Final
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.postgresql.Driver
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:postgresql://127.0.0.1:5432/test]
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {password=****, user=postgres}
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 20 (min=1)
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl logSelectedDialect
INFO: HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
Hibernate: 
    
    alter table if exists employee 
       drop constraint if exists FKsg6w2kdo2j1t3wt0vxta131it
Sep 11, 2022 11:31:21 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@310aee0b] 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 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: relation "employee" does not exist, skipping
Hibernate: 
    
    drop table if exists employee cascade
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: table "employee" does not exist, skipping
Hibernate: 
    
    drop table if exists employee_details cascade
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Sep 11, 2022 11:31:21 AM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: table "employee_details" does not exist, skipping
Hibernate: 
    
    create table employee (
       id integer not null,
        name varchar(255),
        employee_details_id integer,
        primary key (id)
    )
Sep 11, 2022 11:31:21 AM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@29fd8e67] 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 employee_details (
       id integer not null,
        departmentName varchar(255),
        primary key (id)
    )
Hibernate: 
    
    alter table if exists employee 
       add constraint FKsg6w2kdo2j1t3wt0vxta131it 
       foreign key (employee_details_id) 
       references employee_details
Sep 11, 2022 11:31:21 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
        employee_details
        (departmentName, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        employee
        (employee_details_id, name, id) 
    values
        (?, ?, ?)
Hibernate: 
    select
        e1_0.id,
        e1_0.employee_details_id,
        e1_0.name 
    from
        employee e1_0
Employee [id=1, name=Krishna, employeeDetails=EmployeeDetails [id=123, departmentName=Aerospace]]

 

Query PostgreSQL to confirm the DDL.

test=# \d employee
                            Table "public.employee"
       Column        |          Type          | Collation | Nullable | Default 
---------------------+------------------------+-----------+----------+---------
 id                  | integer                |           | not null | 
 name                | character varying(255) |           |          | 
 employee_details_id | integer                |           |          | 
Indexes:
    "employee_pkey" PRIMARY KEY, btree (id)
Foreign-key constraints:
    "fksg6w2kdo2j1t3wt0vxta131it" FOREIGN KEY (employee_details_id) REFERENCES employee_details(id)

test=# 
test=# 
test=# 
test=# \d employee_details
                     Table "public.employee_details"
     Column     |          Type          | Collation | Nullable | Default 
----------------+------------------------+-----------+----------+---------
 id             | integer                |           | not null | 
 departmentname | character varying(255) |           |          | 
Indexes:
    "employee_details_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "employee" CONSTRAINT "fksg6w2kdo2j1t3wt0vxta131it" FOREIGN KEY (employee_details_id) REFERENCES employee_details(id)

 

Query the tables to get information.

test=# SELECT * FROM employee;
 id |  name   | employee_details_id 
----+---------+---------------------
  1 | Krishna |                 123
(1 row)

test=# 
test=# 
test=# SELECT * FROM employee_details;
 id  | departmentname 
-----+----------------
 123 | Aerospace
(1 row)

     

Previous                                                    Next                                                    Home

No comments:

Post a Comment