Generate a serial number with Hibernate (JPA) TableGenerator and store it in the Id of String.

Introduction

When persisting Hibernate Entity, I want to use @GeneratedValue annotation for @Id annotated field and set it to CHAR type column.

However, due to the specifications of the business FW adopted, there is a separate sequence serial number acquisition table (sequence_mng) instead of SEQUENCE of DBMS (SQL Server), and sequence_mng is not used to maintain consistency when creating a new record. It must not be.

The column should be BIGINT too! I think, but it can't be helped because there is something like "zero padding and fixed digit" belief.

Prerequisites

Execution environment

・ JDK1.8 ・ Hibernate (5.2.10.FINAL) · SQL Server 2016

Sequence management table

sequence_mng


CREATE TABLE sequence_mng (
	colname VARCHAR(40) NOT NULL,
	nextvalue BIGINT NOT NULL,
	PRIMARY KEY colname
);

Sequence grant target table

partner


CREATE TABLE m_partner (
	partner_cd CHAR(6) NOT NULL,
	partner_nm NVARCHAR(60) NOT NULL,
        -- OMITTED
        PRIMARY KEY partner_cd
);

Like this, when you try to make it permanent by calling save () etc. -Get the record where the colname of sequence_mng is "partner_cd" -Store nextvalue in partnerCd of Partner.class ・ Next value ++ I want to make it work based on Annotation.

Table Generator trial

And with this pattern, I feel like I can use GenerationType.TABLE. just like this

Partner.java(Failure)


@Entity
@Table(name = "partner")
public class Partner {

    @Id
    @GeneratedValue(strategy = GenerationType.TABLE, generator = "SEQ_TBL_PARTNER")
    @TableGenerator(name = "SEQ_TBL_PARTNER", 
      table = "sequence_mng",
      pkColumnName = "colname",
      valueColumnName = "nextvalue",
      pkColumnValue = "partner_cd")
    @Column(name = "partner_cd", unique = true, nullable = false, length = 6)
    private Integer partnerCd;

    @Column(name = "partner_nm", nullable = false)
    private String partnerNm;
//The following is omitted
}

However, the substance of @TableGenerator org.hibernate.id.enhanced.TableGenerator Actually with'org.hibernate.id.IdentifierGeneratorHelper#getIntegralDataTypeHolder' @Id field does not allow except long (Long), BigDecimal IdentifierGenerationException("Unknown integral data type for ids : StringType()) It doesn't move next to it. As mentioned above, the column attributes cannot be changed.

Customize

Therefore, I will create a StringTableGenerator that inherits TableGenerator and make it work. StringTableGenerator.java Create a StringTableGenerator that inherits from TableGenerator.

StringTableGenerator.java


package sample.hibernate.id;

import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGeneratorHelper;
import org.hibernate.id.IntegralDataTypeHolder;
import org.hibernate.id.enhanced.TableGenerator;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.BigDecimalType;
import org.hibernate.type.Type;

import java.io.Serializable;
import java.util.Properties;

/**
 * TableGenerator (Supports string columns)
 */
public class StringTableGenerator extends TableGenerator {

  @Override
  public void configure(Type type, Properties params, ServiceRegistry serviceRegistry)
    throws MappingException {
    super.configure(new BigDecimalType() , params, serviceRegistry);
  }

  @Override
  public Serializable generate(SharedSessionContractImplementor session, Object obj) {
    return super.generate(session, obj).toString();
  }

}

configure () method

Since StringType comes as the first argument, replace it with BigDecimalType () before passing it to the parent class (^^)

generate () method

The value returned from the parent class is BigDecimal, so replace it with a String before returning it. that's all.

Annotation settings

Then, rewrite the Entity that actually generates the sequence as follows.

Partner.java


@Entity
@Table(name = "partner")
public class Partner implements Serializable {
  @Id
  @GeneratedValue(strategy = GenerationType.TABLE, generator = "CUSTOM_SEQ")
  @GenericGenerator(strategy = "sample.hibernate.id.StringTableGenerator", 
    name = "CUSTOM_SEQ", parameters = {
    @Parameter(name = "segment_value", value = "partner_cd"),
    @Parameter(name = "table_name", value = "sequence_mng"),
    @Parameter(name = "segment_column_name", value = "colname"),
    @Parameter(name = "value_column_name", value = "nextvalue")
  })
  @Column(name = "partner_cd", unique = true, nullable = false, length = 6)
  private String partnerCd;

  @Column(name = "partner_nm", nullable = false)
  private String partnerNm;
 
(The following is omitted)

Change from @TableGenerator, which has a fixed class, to @GenericGenerator, and specify that the StringTableGenerator created earlier should be used. Note that the parameters also change their names.

With the above changes, a serial number will be generated and set in the String field as well.

Finally

Click here for Sequence Generator (almost original material) https://stackoverflow.com/questions/12517421/how-to-map-a-string-to-db-sequence-in-hibernate

Easy-to-understand description of Table Generator http://d.hatena.ne.jp/taedium/20070627/p1

This is also an easy-to-understand Table Generator http://qiita.com/KevinFQ/items/a6d92ec7b32911e50ffe

Digression

Hibernate changes the package structure and class name from time to time, so The materials out there quickly become obsolete.

If you think it's strange-it doesn't move, it's faster to look at the source. This time, the @Parameter name attribute did.

I couldn't find any other TableGenerator and StringType support, so I'll enter it in the hope that it will be useful to someone. then.

Recommended Posts

Generate a serial number with Hibernate (JPA) TableGenerator and store it in the Id of String.
Count the number of occurrences of a string in Ruby
Find the number of days in a month with Kotlin
hibernate composite key
Until the use of Spring Data and JPA Part 2
Until the use of Spring Data and JPA Part 1
Generate a serial number with Hibernate (JPA) TableGenerator and store it in the Id of String.
Summarize the main points of getting started with JPA learned with Hibernate
Defeat the hassle of treating C arrays as Tuples in Swift
How to get the id of PRIMAY KEY auto_incremented in MyBatis
Graph the sensor information of Raspberry Pi in Java and check it with a web browser
How to get the ID of a user authenticated with Firebase in Swift
The nth and n + 1st characters of a Ruby string
[Swift] When you want to know if the number of characters in a String matches a certain number ...
[Rails] Get access_token at the time of Twitter authentication with Sorcery and save it in DB
[Spring Data JPA] Custom ID is assigned in a unique sequence at the time of registration.
Summarize the main points of getting started with JPA learned with Hibernate
[Java] Output the result of ffprobe -show_streams in JSON and map it to an object with Jackson
[Swift] Rather, it is meaningful to avoid var and declare it with let only when there is a branch in the assignment of the initial value.
Dynamically increase the number of elements in a Java 2D array (multidimensional array)
Make a daily build of the TOPPERS kernel with Gitlab and Docker
Set the number of seconds for fast forward and rewind in ExoPlayer
Specify the favorite IP of the host network with docker-compose and start it
I wrote a Lambda function in Java and deployed it with SAM
The identity of params [: id] in rails
Extract a part of a string with Ruby
Split a string with ". (Dot)" in Java
I received the data of the journey (diary application) in Java and visualized it # 001
Created a native extension of Ruby with Rust and published it as a gem
Get YouTube video information with Retrofit and keep it in the Android app.
Create a Yellowfin custom formatter and display the minus of the number as △ (triangle)
Validate the identity token of a user authenticated with AWS Cognito in Java
Be absolutely careful when putting the result of and / or in a variable!
[Java] When putting a character string in the case of a switch statement, it is necessary to make it a constant expression
I want to find the MD5 checksum of a file in Java and get the result as a string in hexadecimal notation.