Saturday, 24 December 2022

Hibernate 6: Embedded id can contain ManyToOne attributes

Embedded ids can contain @ManyToOne attributes.

 

Example

@Entity
@Table(name = "employees")
public class Employee {
    @EmbeddedId
    private EmployeePK empPK;
    
    private String firstName;
    private String lastName;

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


@Entity
@Table(name = "project")
public class Project {

    @Id
    private Integer id;

    private String name;

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

@Embeddable
public class EmployeePK implements Serializable {
    private int empId;
    private int deptId;

    @ManyToOne(fetch = FetchType.LAZY)
    private Project project;

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

 

Find the below working application.

 

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

 

Step 2: Update pom.xml with maven dependenices.

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-composite-id-many-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.

 

Project.java

package com.sample.app.entity;

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

@Entity
@Table(name = "project")
public class Project {

    @Id
    private Integer id;

    private String name;

    public Project(Integer id, String name) {
        this.id = id;
        this.name = name;
    }

    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;
    }

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

}

 

EmployeePK.java

package com.sample.app.entity;

import java.io.Serializable;

import jakarta.persistence.Embeddable;
import jakarta.persistence.FetchType;
import jakarta.persistence.ManyToOne;

@Embeddable
public class EmployeePK implements Serializable {
    private int empId;
    private int deptId;

    @ManyToOne(fetch = FetchType.LAZY)
    private Project project;

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public int getDeptId() {
        return deptId;
    }

    public void setDeptId(int deptId) {
        this.deptId = deptId;
    }

    public Project getProject() {
        return project;
    }

    public void setProject(Project project) {
        this.project = project;
    }

    @Override
    public String toString() {
        return "EmployeePK [empId=" + empId + ", deptId=" + deptId + "]";
    }

}

 

Employee.java

package com.sample.app.entity;

import jakarta.persistence.EmbeddedId;
import jakarta.persistence.Entity;
import jakarta.persistence.Table;

@Entity
@Table(name = "employees")
public class Employee {
    @EmbeddedId
    private EmployeePK empPK;
    
    private String firstName;
    private String lastName;

    public EmployeePK getEmpPK() {
        return empPK;
    }

    public void setEmpPK(EmployeePK empPK) {
        this.empPK = empPK;
    }

    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 [empPK=" + empPK + ", firstName=" + firstName + ", lastName=" + lastName + "]";
    }
    
    

}

 

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.Project" />

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

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[]) {

        Project project = new Project(1, "CPCS");

        EmployeePK empPk = new EmployeePK();
        empPk.setDeptId(1);
        empPk.setEmpId(23);

        Employee emp = new Employee();
        emp.setEmpPK(empPk);
        emp.setFirstName("Lakshmana Rao");
        emp.setLastName("Gurram");

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

            session.persist(project);
            session.flush();

            Project persistedPjt = session.find(Project.class, 1);
            emp.getEmpPK().setProject(persistedPjt);

            session.persist(emp);

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

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

    }
}

 

Total project structure looks like below.

 

 



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

Aug 24, 2022 3:50:10 PM org.hibernate.Version logVersion
INFO: HHH000412: Hibernate ORM core version 6.1.2.Final
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure
WARN: HHH10001002: Using built-in connection pool (not intended for production use)
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001005: Loaded JDBC driver class: org.postgresql.Driver
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001012: Connecting with JDBC URL [jdbc:postgresql://127.0.0.1:5432/test]
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001001: Connection properties: {password=****, user=postgres}
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator
INFO: HHH10001003: Autocommit mode: false
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init>
INFO: HHH10001115: Connection pool size: 20 (min=1)
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.dialect.internal.DialectFactoryImpl logSelectedDialect
INFO: HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
Aug 24, 2022 3:50:11 PM org.hibernate.mapping.RootClass checkCompositeIdentifier
WARN: HHH000038: Composite-id class does not override equals(): com.sample.app.entity.EmployeePK
Aug 24, 2022 3:50:11 PM org.hibernate.mapping.RootClass checkCompositeIdentifier
WARN: HHH000039: Composite-id class does not override hashCode(): com.sample.app.entity.EmployeePK
Aug 24, 2022 3:50:11 PM org.hibernate.metamodel.internal.EntityInstantiatorPojoStandard resolveConstructor
INFO: HHH000182: No default (no-argument) constructor for class: com.sample.app.entity.Project (class must be instantiated by Interceptor)
Hibernate: 
    
    alter table if exists employees 
       drop constraint if exists FK2tel0rbca80y6ag0ye49o106m
Aug 24, 2022 3:50:11 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@52b06bef] 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.
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: relation "employees" does not exist, skipping
Hibernate: 
    
    drop table if exists employees cascade
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: table "employees" does not exist, skipping
Hibernate: 
    
    drop table if exists project cascade
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: SQL Warning Code: 0, SQLState: 00000
Aug 24, 2022 3:50:11 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper$StandardWarningHandler logWarning
WARN: table "project" does not exist, skipping
Hibernate: 
    
    create table employees (
       deptId integer not null,
        empId integer not null,
        firstName varchar(255),
        lastName varchar(255),
        project_id integer not null,
        primary key (deptId, empId, project_id)
    )
Aug 24, 2022 3:50:11 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection
INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@2f9a4401] 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 project (
       id integer not null,
        name varchar(255),
        primary key (id)
    )
Hibernate: 
    
    alter table if exists employees 
       add constraint FK2tel0rbca80y6ag0ye49o106m 
       foreign key (project_id) 
       references project
Aug 24, 2022 3:50:11 PM 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
        project
        (name, id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        employees
        (firstName, lastName, deptId, empId, project_id) 
    values
        (?, ?, ?, ?, ?)
Hibernate: 
    select
        e1_0.deptId,
        e1_0.empId,
        e1_0.project_id,
        e1_0.firstName,
        e1_0.lastName 
    from
        employees e1_0
Employee [empPK=EmployeePK [empId=23, deptId=1], firstName=Lakshmana Rao, lastName=Gurram]
Project [id=1, name=CPCS]

Query the database for tables structure.

test=# \d+ employees;
                                                  Table "public.employees"
   Column   |          Type          | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
------------+------------------------+-----------+----------+---------+----------+-------------+--------------+-------------
 deptid     | integer                |           | not null |         | plain    |             |              | 
 empid      | integer                |           | not null |         | plain    |             |              | 
 firstname  | character varying(255) |           |          |         | extended |             |              | 
 lastname   | character varying(255) |           |          |         | extended |             |              | 
 project_id | integer                |           | not null |         | plain    |             |              | 
Indexes:
    "employees_pkey" PRIMARY KEY, btree (deptid, empid, project_id)
Foreign-key constraints:
    "fk2tel0rbca80y6ag0ye49o106m" FOREIGN KEY (project_id) REFERENCES project(id)
Access method: heap

test=# 
test=# 
test=# \d+ project
                                                 Table "public.project"
 Column |          Type          | Collation | Nullable | Default | Storage  | Compression | Stats target | Description 
--------+------------------------+-----------+----------+---------+----------+-------------+--------------+-------------
 id     | integer                |           | not null |         | plain    |             |              | 
 name   | character varying(255) |           |          |         | extended |             |              | 
Indexes:
    "project_pkey" PRIMARY KEY, btree (id)
Referenced by:
    TABLE "employees" CONSTRAINT "fk2tel0rbca80y6ag0ye49o106m" FOREIGN KEY (project_id) REFERENCES project(id)
Access method: heap

You can download the application from this link.


 

Previous                                                    Next                                                    Home

No comments:

Post a Comment