How to generate Custom Id using hibernate while it must be primary key of table

Solution 1:

Thank you everyone for your response...... finally i have done some changes in my Department class and used a class for generating ids........Here is my code

@Entity
public class Department {

@Id
@GenericGenerator(name = "sequence_dep_id", strategy = "com.xyz.ids.DepartmentIdGenerator")
@GeneratedValue(generator = "sequence_dep_id")  
@Column(name="Department_Id")
private String deptId;

@Column(name="Department_Name",unique=true,nullable=false)
private String deptName;


@Column(name="Department_Description")
@NotNull
private String deptDesc;

//getters and setters

DepartmentIdGenerator.java

package com.xyz.ids;

import java.io.Serializable;
import java.sql.*;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;

public class DepartmentIdGenerator implements IdentifierGenerator{

    @Override
    public Serializable generate(SessionImplementor session, Object object)
            throws HibernateException {

        String prefix = "DEP";
        Connection connection = session.connection();

        try {
            Statement statement=connection.createStatement();

            ResultSet rs=statement.executeQuery("select count(Department_Id) as Id from demo.Department");

            if(rs.next())
            {
                int id=rs.getInt(1)+101;
                String generatedId = prefix + new Integer(id).toString();
                System.out.println("Generated Id: " + generatedId);
                return generatedId;
            }
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }


        return null;
    }

}

Solution 2:

The best way to implement custom id generator in Hibernate.

@Entity
@Table(name = "employee_customid")
public class Employee implements Serializable {
@Id
@GenericGenerator(name = "string_based_custom_sequence", strategy = 
"com.ie.customid.EmployeeIdGenerator")
@GeneratedValue(generator = "string_based_custom_sequence")
@Column(name = "custom_emp_id")
private String id;

@Column(name = "emp_name")
private String name;
@Column(name = "emp_age")
private Integer age;
@Column(name = "emp_salary")
private Double salary;
// getter setter and toString

Below code is implementation for generating custom id in hibernate with any database code will be same (with minimal changes)

package com.ie.customid;

import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.id.IdentifierGenerator;

import java.io.Serializable;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class EmployeeIdGenerator implements IdentifierGenerator {
    //You can give any name to sequence be sure that you know how to use it.
    private final String DEFAULT_SEQUENCE_NAME = "hibernate_sequence";
    //private final String DEFAULT_SEQUENCE_NAME = "hib_sequence";

    /*
    * This method will generate custom id based on String followed by id
    * e.g. emp0001, emp0002, emp0003 and so on..
    * */
    public Serializable generate(SessionImplementor session, Object object) throws HibernateException {
        Serializable result = null;
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;

        String prefix = "emp";
        try {
            connection = session.connection();
            statement = connection.createStatement();
            try {
                /*
                * uncomment below line if you are using mysql and the sequence DOES NOT EXIST.
                * As we all know MySql does not support sequence, instead there is AUTO INCREMENT
                * if you are using other databases change SQL according to that
                * e.g. Oracle: "SELECT "+sequenceName+".NEXTVAL FROM DUAL"
                * PostgreSQL: "SELECT  NEXTVAL('+sequenceName+"')  
                * */
                //statement.executeUpdate("UPDATE " + DEFAULT_SEQUENCE_NAME + " SET next_val=LAST_INSERT_ID(next_val+1)");
                resultSet = statement.executeQuery("SELECT next_val FROM  " + DEFAULT_SEQUENCE_NAME);
            } catch (Exception e) {

                System.out.println("In catch, cause : Table is not available.");
                // if sequence is not found then creating the sequence
                // Below code is for MySql database you change according to your database
                statement.execute("CREATE table " + DEFAULT_SEQUENCE_NAME + " (next_val INT NOT NULL)");
                statement.executeUpdate("INSERT INTO " + DEFAULT_SEQUENCE_NAME + " VALUES(0)");
                //==> LAST_INSERT_ID(next_val+1)  -> this is inbuilt function of MySql so by using this we can achieve our custom sequence like auto increment
                statement.executeUpdate("UPDATE " + DEFAULT_SEQUENCE_NAME + " SET next_val=LAST_INSERT_ID(next_val+1)");
                resultSet = statement.executeQuery("SELECT next_val FROM  " + DEFAULT_SEQUENCE_NAME);
                //e.printStackTrace();
            }
            if (resultSet.next()) {

                int nextValue = resultSet.getInt(1);
                String suffix = String.format("%04d", nextValue);
                result = prefix.concat(suffix);
                System.out.println("Custom generated sequence is : " + result);
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return result;
    }
}

If you like to use XML configuration then use below code

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hbm2ddl.auto">update</property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/Testing</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <mapping class="com.ie.entity.Employee"/>
        <!-- uncomment below line if you want to use XML based mapping & NOTE :  if you will use both then XML will override annotation  -->
<!--        <mapping resource="Employee.hbm.xml"></mapping>-->
    </session-factory>
</hibernate-configuration>

Below is Employee mapping file

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
        "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">

<hibernate-mapping>
    <class name="com.ie.entity.Employee" table="employees_customid">
        <id name="id" column="employeeId">
            <generator class="com.ie.customid.EmployeeIdGenerator"/>
        </id>
        <property name="name" column="e_name"></property>
        <property name="age" column="e_age"/>
        <property name="salary" column="e_salary"/>
    </class>
</hibernate-mapping>