In our previous example, we have seen how to create a Composite key in Hibernate using <composite-id> tag and Annotations. In this Embeddable Composite Primary Key example, we will be declaring the IDs (Primary Key fields) as a separate class annotated with @Embeddable annotation. An Employee is identified by its EmployeeId, which is defined by empId and department. Let’s dig into the code…
Hibernate Embeddable Composite Primary Key
Creating table
Create EMPLOYEE Table, simply Copy and Paste the following SQL query in the query editor to get the table created.
CREATE TABLE "EMPLOYEE" ( "EMP_ID" NUMBER(10,0) NOT NULL ENABLE, "EMP_NAME" VARCHAR2(255 CHAR), "DEPARTMENT" VARCHAR2(255 CHAR), PRIMARY KEY(EMP_ID,DEPARTMENT) );
Folder Structure:
- Create a simple Maven Project “HibernateTutorial” and create a package for our source files “com.javainterviewpoint” under src/main/java
- Now add the following dependency in the 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 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>HibernateTutorial</groupId> <artifactId>HibernateTutorial</artifactId> <version>0.0.1-SNAPSHOT</version> <properties> <hibernate.version>4.3.11.Final</hibernate.version> <oracle.connector.version>11.2.0</oracle.connector.version> </properties> <dependencies> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <!-- Oracle --> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc14</artifactId> <version>${oracle.connector.version}</version> </dependency> </dependencies> <build> <sourceDirectory>src</sourceDirectory> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>3.3</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> </plugins> </build> </project>
- Create the Java classes Employee.java, EmployeeId.java and CompositeKey_Embeddable_Example.java under com.javainterviewpoint folder.
- Place the hibernate.cfg.xml under the src/main/resources directory
EmployeeId.java
package com.javainterviewpoint; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Embeddable; @Embeddable public class EmployeeId implements Serializable { private static final long serialVersionUID = 1L; @Column(name = "EMP_ID") private int empId; @Column(name = "DEPARTMENT") private String department; public EmployeeId() { super(); } public EmployeeId(int empId, String department) { super(); this.empId = empId; this.department = department; } public int getEmpId() { return empId; } public void setEmpId(int empId) { this.empId = empId; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + ((department == null) ? 0 : department.hashCode()); result = prime * result + empId; return result; } @Override public boolean equals(Object obj) { if (this == obj) return true; if (obj == null) return false; if (getClass() != obj.getClass()) return false; EmployeeId other = (EmployeeId) obj; if (department == null) { if (other.department != null) return false; } else if (!department.equals(other.department)) return false; if (empId != other.empId) return false; return true; } }
In order to implement Composite Key in Hibernate, we need to override the equals() and hashCode() method and also implement the Serializable interface. Our EmployeeId class act as the ID class and we have marked it with @Embeddable annotation so that this class is eligible to be an embeddable class.
Employee.java
package com.javainterviewpoint; import java.io.Serializable; import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.Id; @Entity public class Employee implements Serializable { private static final long serialVersionUID = 1L; @EmbeddedId EmployeeId id; @Column(name="EMP_NAME") private String empName; public Employee() { super(); } public Employee(EmployeeId id, String empName) { super(); this.id = id; this.empName = empName; } public EmployeeId getId() { return id; } public void setId(EmployeeId id) { this.id = id; } public String getEmpName() { return empName; } public void setEmpName(String empName) { this.empName = empName; } }
Our primary key fields(empId and department) are defined in our embeddable class (EmployeeId). The Employee Entity class contains a single primary key field (EmployeeId) that is annotated with @EmbeddedId and contains an instance of that embeddable class.
hibernate.cfg.xml
Place the hibernate.cfg.xml file also under the src/main/resources folder
<?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="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property> <property name="hibernate.connection.url">jdbc:oracle:thin:@mydb:40051:dev</property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect --> <property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- Drop and re-create the database schema on startup --> <property name="hibernate.hbm2ddl.auto">update</property> <!-- Mapping class --> <mapping class="com.javainterviewpoint.Employee"/> <mapping class="com.javainterviewpoint.EmployeeId"/> </session-factory> </hibernate-configuration>
- First and foremost property is for specifying the JDBC Driver class, in my case it OracleDriver
<property name="hibernate.connection.driver_class">oracle.jdbc.driver.OracleDriver</property>
- Give the connection URL for connecting the database and provide username and password for connecting the above database
<property name="hibernate.connection.url">jdbc:oracle:thin:@mydb:40051:dev</property> <property name="hibernate.connection.username">root</property> <property name="hibernate.connection.password">root</property>
- Specify the connection pool size, this property limits the number of connections in the Hibernate connection pool.
<property name="connection.pool_size">1</property>
- Dialect Property makes the Hibernate generate the SQL for the corresponding database which is being used. In this example we are using Oracle database hence Oracle query will be generated. If you are using MySQL database then you need to change the dialect accordingly.
<property name="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</property>
- The show_sql property will print the executed sql in the console when set to true.
<property name="show_sql">true</property>
- If the property “hibernate.hbm2ddl.auto” is set to “create” This will drop and recreate the database schema on every execution. If it is set to “update” then the database schema will be updated every time rather than dropping and recreating.
<property name="hibernate.hbm2ddl.auto">update</property>
- Under the Mapping resource tag, we need to specify all the mapping class for which we need the table to be created or updated.
<mapping class="com.javainterviewpoint.Employee"/> <mapping class="com.javainterviewpoint.EmployeeId"/>
CompositeKey_Embeddable_Example.java
package com.javainterviewpoint; import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.service.ServiceRegistry; public class CompositeKey_Embeddable_Example { public static void main(String args[]) { //Reading the hibernate configuration file Configuration configuration = new Configuration().configure("hibernate.cfg.xml"); StandardServiceRegistryBuilder regBuilber = new StandardServiceRegistryBuilder(); regBuilber.applySettings(configuration.getProperties()); ServiceRegistry serviceRegistry = regBuilber.build(); //Create SessionFacctory SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry); //Create Session from SessionFactory Session session = sessionFactory.openSession(); //Begin the transaction session.beginTransaction(); //Create a new Employee object Employee employee = new Employee(); EmployeeId employeeId = new EmployeeId(1,"Blogging"); employee.setEmpName("JavaInterviewPoint"); employee.setId(employeeId); session.save(employee); //Retrieve Employee Details Employee employee1 = (Employee) session.get(Employee.class, employeeId); System.out.println("*** Employee Details ***"); System.out.println("Employee Id : "+employee1.getId().getEmpId()); System.out.println("Employee Name : "+employee1.getEmpName()); System.out.println("Department : "+employee1.getId().getDepartment()); //Commit the changes session.getTransaction().commit(); //Close the session session.close(); } }
- Create the Configuration object and read the configuration file using the configure() method.
Configuration configuration = new Configuration().configure("hibernate.cfg.xml");
- Get the SessionFactory object through the buildSessionFactory() method of the configuration object.
SessionFactory sessionFactory = configuration.buildSessionFactory(serviceRegistry);
- openSession() method opens up the new session and begin a new transaction
Session session = sessionFactory.openSession(); session.beginTransaction();
- Create Employee and EmployeeId object and set values to its properties
//Create a new Employee object Employee employee = new Employee(); //set value to its properties EmployeeId employeeId = new EmployeeId(1,"Blogging"); employee.setEmpName("JavaInterviewPoint"); employee.setId(employeeId);
- save() method of the session object will persist the Employee object
session.save(employee);
- We can retrieve the Employee details by just passing ID class (EmployeeId)
Employee employee1 = (Employee) session.get(Employee.class, employeeId); System.out.println("*** Employee Details ***"); System.out.println("Employee Id : "+employee1.getId().getEmpId()); System.out.println("Employee Name : "+employee1.getEmpName()); System.out.println("Department : "+employee1.getId().getDepartment());
- Finally get the transaction and commit the changes and close the session.
session.getTransaction().commit(); session.close();
Console
INFO: HHH000261: Table found: EMPLOYEE Mar 23, 2017 6:33:07 AM org.hibernate.tool.hbm2ddl.TableMetadata INFO: HHH000037: Columns: [department, emp_name, emp_id] Mar 23, 2017 6:33:07 AM org.hibernate.tool.hbm2ddl.TableMetadata INFO: HHH000108: Foreign keys: [] Mar 23, 2017 6:33:07 AM org.hibernate.tool.hbm2ddl.TableMetadata INFO: HHH000126: Indexes: [sys_c0015248] Mar 23, 2017 6:33:07 AM org.hibernate.tool.hbm2ddl.SchemaUpdate execute INFO: HHH000232: Schema update complete *** Employee Details *** Employee Id : 1 Employee Name : JavaInterviewPoint Department : Blogging Hibernate: insert into EMPLOYEE (EMP_NAME, EMP_ID, DEPARTMENT) values (?, ?, ?)
Table
Vishal says
To the point and simple to understand